gtk2/gtk/gtkcolorsel.c
Padraig O'Briain 5bc235001a Change popup_menu signal to return gboolean instead of void. This allows
* gtk/gtkwidget.[ch]:
Change popup_menu signal to return gboolean instead of void. This
allows the keypress which invokes the signal to be propagated to the
focus widgets ancestors if not handled by the focus widget.

* gtk/gtkcolorsel.c gtk/gtkentry.c gtk/gtktextview.c:
Change signature of popup_menu signal handler to return gboolean
instead of void and return TRUE in the signal handler
2002-02-07 09:39:21 +00:00

2764 lines
79 KiB
C

/* 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
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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-2001. 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 "gdkconfig.h"
#include <math.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 "gtkmarshalers.h"
#include "gtkpixmap.h"
#include "gtkspinbutton.h"
#include "gtkrange.h"
#include "gtkhscale.h"
#include "gtkentry.h"
#include "gtkbutton.h"
#include "gtkhseparator.h"
#include "gtktooltips.h"
#include "gtkinvisible.h"
#include "gtkmenuitem.h"
#include "gtkmain.h"
#include "gtksettings.h"
#include "gtkintl.h"
#include <string.h>
/* Number of elements in the custom palatte */
#define GTK_CUSTOM_PALETTE_WIDTH 10
#define GTK_CUSTOM_PALETTE_HEIGHT 2
/* Conversion between 0->1 double and and guint16. See
* scale_round() below for more general conversions
*/
#define SCALE(i) (i / 65535.)
#define UNSCALE(d) ((guint16)(d * 65535 + 0.5))
enum {
COLOR_CHANGED,
LAST_SIGNAL
};
enum {
PROP_0,
PROP_HAS_PALETTE,
PROP_HAS_OPACITY_CONTROL,
PROP_CURRENT_COLOR,
PROP_CURRENT_ALPHA,
};
enum {
COLORSEL_RED = 0,
COLORSEL_GREEN = 1,
COLORSEL_BLUE = 2,
COLORSEL_OPACITY = 3,
COLORSEL_HUE,
COLORSEL_SATURATION,
COLORSEL_VALUE,
COLORSEL_NUM_CHANNELS
};
typedef struct _ColorSelectionPrivate ColorSelectionPrivate;
struct _ColorSelectionPrivate
{
guint has_opacity : 1;
guint has_palette : 1;
guint changing : 1;
guint default_set : 1;
guint default_alpha_set : 1;
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 [GTK_CUSTOM_PALETTE_WIDTH][GTK_CUSTOM_PALETTE_HEIGHT];
/* The color_sample stuff */
GtkWidget *sample_area;
GtkWidget *old_sample;
GtkWidget *cur_sample;
GtkWidget *colorsel;
/* Tooltips group */
GtkTooltips *tooltips;
/* Window for grabbing on */
GtkWidget *dropper_grab_widget;
/* Connection to settings */
guint settings_connection;
};
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 gtk_color_selection_finalize (GObject *object);
static void gtk_color_selection_realize (GtkWidget *widget);
static void update_color (GtkColorSelection *colorsel);
static void gtk_color_selection_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gtk_color_selection_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static gint gtk_color_selection_get_palette_size (GtkColorSelection *colorsel);
static gboolean gtk_color_selection_get_palette_color (GtkColorSelection *colorsel,
gint index,
GdkColor *color);
static void gtk_color_selection_set_palette_color (GtkColorSelection *colorsel,
gint index,
GdkColor *color);
static void gtk_color_selection_unset_palette_color (GtkColorSelection *colorsel,
gint index);
static GdkGC *get_focus_gc (GtkWidget *drawing_area,
gint *focus_width);
static void default_change_palette_func (const GdkColor *colors,
gint n_colors);
static gpointer parent_class = NULL;
static guint color_selection_signals[LAST_SIGNAL] = { 0 };
static gchar* default_colors = "black:white:gray50:red:purple:blue:light blue:green:yellow:orange:lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90";
static GtkColorSelectionChangePaletteFunc change_palette_hook = default_change_palette_func;
static GdkColor current_colors[GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT];
/* 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 */
"#########################",
"#########################",
"#########################",
"#########################",
"#########################",
"################# #####",
"################ ####",
"################ +###",
"############# +###",
"############## ++###",
"#############+@ +++####",
"############+@@@ +######",
"###########+@@@ + +######",
"##########+@@@ ++#+######",
"#########+@@@ ++#########",
"########+@@@ ++##########",
"#######+@@@ ++###########",
"######+@@@ ++############",
"######+@@ ++#############",
"#####+@ ++##############",
"###### +++###############",
"#########################",
"#########################",
"#########################",
"#########################"
};
/*
*
* 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
color_sample_drag_begin (GtkWidget *widget,
GdkDragContext *context,
gpointer data)
{
GtkColorSelection *colorsel = data;
ColorSelectionPrivate *priv;
GtkWidget *window;
gdouble colors[4];
gdouble *colsrc;
GdkColor bg;
gint n, i;
priv = colorsel->private_data;
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);
if (widget == priv->old_sample)
colsrc = priv->old_color;
else
colsrc = priv->color;
for (i=0, n = COLORSEL_RED; n <= COLORSEL_BLUE; n++)
{
colors[i++] = colsrc[n];
}
if (priv->has_opacity)
{
colors[i] = colsrc[COLORSEL_OPACITY];
}
bg.red = 0xffff * colors[0];
bg.green = 0xffff * colors[1];
bg.blue = 0xffff * colors[2];
gdk_color_alloc (gtk_widget_get_colormap (window), &bg);
gdk_window_set_background (window->window, &bg);
gtk_drag_set_icon_widget (context, window, -2, -2);
}
static void
color_sample_drag_end (GtkWidget *widget,
GdkDragContext *context,
gpointer data)
{
gtk_object_set_data (GTK_OBJECT (widget), "gtk-color-selection-drag-window", NULL);
}
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_data;
/* This is currently a guint16 array of the format:
* R
* G
* B
* opacity
*/
if (selection_data->length < 0)
return;
if ((selection_data->format != 16) ||
(selection_data->length != 8))
{
g_warning ("Received invalid color data\n");
return;
}
vals = (guint16 *)selection_data->data;
if (widget == priv->cur_sample)
{
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
color_sample_drag_handle (GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *selection_data,
guint info,
guint time,
gpointer data)
{
GtkColorSelection *colorsel = data;
ColorSelectionPrivate *priv;
guint16 vals[4];
gdouble *colsrc;
priv = colorsel->private_data;
if (widget == priv->old_sample)
colsrc = priv->old_color;
else
colsrc = priv->color;
vals[0] = colsrc[COLORSEL_RED] * 0xffff;
vals[1] = colsrc[COLORSEL_GREEN] * 0xffff;
vals[2] = colsrc[COLORSEL_BLUE] * 0xffff;
vals[3] = priv->has_opacity ? colsrc[COLORSEL_OPACITY] * 0xffff : 0xffff;
gtk_selection_data_set (selection_data,
gdk_atom_intern ("application/x-color", FALSE),
16, (guchar *)vals, 8);
}
/* which = 0 means draw old sample, which = 1 means draw new */
static void
color_sample_draw_sample (GtkColorSelection *colorsel, int which)
{
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_data;
g_return_if_fail (priv->sample_area != NULL);
if (!GTK_WIDGET_DRAWABLE (priv->sample_area))
return;
if (which == 0)
{
da = priv->old_sample;
for (n = 0, i = COLORSEL_RED; n < 3; n++, i++)
c[n] = (guchar) (UNSCALE (priv->old_color[i]) >> 8);
goff = 0;
}
else
{
da = priv->cur_sample;
for (n = 0, i = COLORSEL_RED; n < 3; n++, i++)
c[n] = (guchar) (UNSCALE (priv->color[i]) >> 8);
goff = priv->old_sample->allocation.width % 32;
}
wid = da->allocation.width;
heig = da->allocation.height;
buf = g_new (guchar, 3 * wid * heig);
#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
if (priv->has_opacity)
{
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;
}
i = 0;
for (y = 0; y < heig; y++)
{
for (x = 0; x < wid; x++)
{
if (priv->has_opacity)
f = 3 * ((((goff + x) % 32) < 16) ^ ((y % 32) < 16));
else
f = 0;
for (n = 0; n < 3; n++)
buf[i++] = cp[n + f];
}
}
gdk_draw_rgb_image (da->window,
da->style->black_gc,
0, 0,
wid, heig,
GDK_RGB_DITHER_NORMAL,
buf,
3*wid);
g_free (buf);
}
static void
color_sample_draw_samples (GtkColorSelection *colorsel)
{
color_sample_draw_sample (colorsel, 0);
color_sample_draw_sample (colorsel, 1);
}
static gboolean
color_old_sample_expose (GtkWidget *da,
GdkEventExpose *event,
GtkColorSelection *colorsel)
{
color_sample_draw_sample (colorsel, 0);
return FALSE;
}
static gboolean
color_cur_sample_expose (GtkWidget *da,
GdkEventExpose *event,
GtkColorSelection *colorsel)
{
color_sample_draw_sample (colorsel, 1);
return FALSE;
}
static void
color_sample_setup_dnd (GtkColorSelection *colorsel, GtkWidget *sample)
{
static const GtkTargetEntry targets[] = {
{ "application/x-color", 0 }
};
ColorSelectionPrivate *priv;
priv = colorsel->private_data;
gtk_drag_source_set (sample,
GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
targets, 1,
GDK_ACTION_COPY | GDK_ACTION_MOVE);
gtk_signal_connect (GTK_OBJECT (sample),
"drag_begin",
GTK_SIGNAL_FUNC (color_sample_drag_begin),
colorsel);
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 (color_sample_drag_handle),
colorsel);
gtk_signal_connect (GTK_OBJECT (sample),
"drag_data_received",
GTK_SIGNAL_FUNC (color_sample_drop_handle),
colorsel);
}
static void
color_sample_new (GtkColorSelection *colorsel)
{
ColorSelectionPrivate *priv;
priv = colorsel->private_data;
priv->sample_area = gtk_hbox_new (FALSE, 0);
priv->old_sample = gtk_drawing_area_new ();
priv->cur_sample = gtk_drawing_area_new ();
/* We need enter/leave to do tooltips */
gtk_widget_add_events (priv->old_sample,
GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
gtk_widget_add_events (priv->cur_sample,
GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
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_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);
color_sample_setup_dnd (colorsel, priv->old_sample);
color_sample_setup_dnd (colorsel, priv->cur_sample);
gtk_tooltips_set_tip (priv->tooltips,
priv->old_sample,
_("The previously-selected color, for comparison to the color you're selecting now. You can drag this color to a palette entry, or select this color as current by dragging it to the other color swatch alongside."), NULL);
gtk_tooltips_set_tip (priv->tooltips,
priv->cur_sample,
_("The color you've chosen. You can drag this color to a palette entry to save it for use in the future."), NULL);
gtk_widget_show_all (priv->sample_area);
}
/*
*
* The palette area code
*
*/
#define CUSTOM_PALETTE_ENTRY_WIDTH 20
#define CUSTOM_PALETTE_ENTRY_HEIGHT 20
static void
palette_get_color (GtkWidget *drawing_area, gdouble *color)
{
gdouble *color_val;
g_return_if_fail (color != NULL);
color_val = gtk_object_get_data (GTK_OBJECT (drawing_area), "color_val");
if (color_val == NULL)
{
/* 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
palette_paint (GtkWidget *drawing_area,
GdkRectangle *area,
gpointer data)
{
if (drawing_area->window == NULL)
return;
gdk_window_clear_area (drawing_area->window,
area->x,
area->y,
area->width,
area->height);
if (GTK_WIDGET_HAS_FOCUS (drawing_area))
{
gint focus_width;
GdkGC *gc = get_focus_gc (drawing_area, &focus_width);
gdk_draw_rectangle (drawing_area->window,
gc, FALSE, focus_width / 2, focus_width / 2,
drawing_area->allocation.width - focus_width,
drawing_area->allocation.height - focus_width);
g_object_unref (gc);
}
}
static GdkGC *
get_focus_gc (GtkWidget *drawing_area,
gint *focus_width)
{
GdkGC *gc = gdk_gc_new (drawing_area->window);
gdouble color[4];
gint8 *dash_list;
gtk_widget_style_get (drawing_area,
"focus-line-width", focus_width,
"focus-line-pattern", (gchar *)&dash_list,
NULL);
palette_get_color (drawing_area, color);
if (INTENSITY (color[0], color[1], color[2]) > 0.5)
gdk_gc_copy (gc, drawing_area->style->black_gc);
else
gdk_gc_copy (gc, drawing_area->style->white_gc);
gdk_gc_set_line_attributes (gc, *focus_width,
dash_list[0] ? GDK_LINE_ON_OFF_DASH : GDK_LINE_SOLID,
GDK_CAP_BUTT, GDK_JOIN_MITER);
if (dash_list[0])
gdk_gc_set_dashes (gc, 0, dash_list, strlen (dash_list));
g_free (dash_list);
return gc;
}
static void
palette_drag_begin (GtkWidget *widget,
GdkDragContext *context,
gpointer data)
{
GtkColorSelection *colorsel = data;
ColorSelectionPrivate *priv;
GtkWidget *window;
gdouble colors[4];
GdkColor bg;
priv = colorsel->private_data;
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);
palette_get_color (widget, colors);
bg.red = 0xffff * colors[0];
bg.green = 0xffff * colors[1];
bg.blue = 0xffff * colors[2];
gdk_color_alloc (gtk_widget_get_colormap (window), &bg);
gdk_window_set_background (window->window, &bg);
gtk_drag_set_icon_widget (context, window, -2, -2);
}
static void
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_drag_end (GtkWidget *widget,
GdkDragContext *context,
gpointer data)
{
gtk_object_set_data (GTK_OBJECT (widget), "gtk-color-selection-drag-window", NULL);
}
/* Changes the model color */
static void
palette_change_color (GtkWidget *drawing_area,
GtkColorSelection *colorsel,
gdouble *color)
{
gint x, y;
ColorSelectionPrivate *priv;
GdkColor gdk_color;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
g_return_if_fail (GTK_IS_DRAWING_AREA (drawing_area));
priv = colorsel->private_data;
gdk_color.red = UNSCALE (color[0]);
gdk_color.green = UNSCALE (color[1]);
gdk_color.blue = UNSCALE (color[2]);
x = 0;
while (x < GTK_CUSTOM_PALETTE_WIDTH)
{
y = 0;
while (y < GTK_CUSTOM_PALETTE_HEIGHT)
{
if (priv->custom_palette[x][y] == drawing_area)
goto out;
++y;
}
++x;
}
out:
g_assert (x < GTK_CUSTOM_PALETTE_WIDTH || y < GTK_CUSTOM_PALETTE_HEIGHT);
current_colors[y * GTK_CUSTOM_PALETTE_WIDTH + x] = gdk_color;
if (change_palette_hook)
(* change_palette_hook) (current_colors, GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
}
/* Changes the view color */
static void
palette_set_color (GtkWidget *drawing_area,
GtkColorSelection *colorsel,
gdouble *color)
{
gdouble *new_color = g_new (double, 4);
GdkColor gdk_color;
gdk_color.red = UNSCALE (color[0]);
gdk_color.green = UNSCALE (color[1]);
gdk_color.blue = UNSCALE (color[2]);
gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, &gdk_color);
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));
}
new_color[0] = color[0];
new_color[1] = color[1];
new_color[2] = color[2];
new_color[3] = 1.0;
g_object_set_data_full (G_OBJECT (drawing_area), "color_val", new_color, (GDestroyNotify)g_free);
}
static gboolean
palette_expose (GtkWidget *drawing_area,
GdkEventExpose *event,
gpointer data)
{
if (drawing_area->window == NULL)
return FALSE;
palette_paint (drawing_area, &(event->area), data);
return FALSE;
}
static void
popup_position_func (GtkMenu *menu,
gint *x,
gint *y,
gboolean *push_in,
gpointer user_data)
{
GtkWidget *widget;
GtkRequisition req;
gint root_x, root_y;
widget = GTK_WIDGET (user_data);
g_return_if_fail (GTK_WIDGET_REALIZED (widget));
gdk_window_get_origin (widget->window, &root_x, &root_y);
gtk_widget_size_request (GTK_WIDGET (menu), &req);
/* Put corner of menu centered on color cell */
*x = root_x + widget->allocation.width / 2;
*y = root_y + widget->allocation.height / 2;
/* Ensure sanity */
*x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width));
*y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height));
}
static void
save_color_selected (GtkWidget *menuitem,
gpointer data)
{
GtkColorSelection *colorsel;
GtkWidget *drawing_area;
ColorSelectionPrivate *priv;
drawing_area = GTK_WIDGET (data);
colorsel = GTK_COLOR_SELECTION (g_object_get_data (G_OBJECT (drawing_area),
"gtk-color-sel"));
priv = colorsel->private_data;
palette_change_color (drawing_area, colorsel, priv->color);
}
static void
do_popup (GtkColorSelection *colorsel,
GtkWidget *drawing_area,
guint32 timestamp)
{
GtkWidget *menu;
GtkWidget *mi;
g_object_set_data (G_OBJECT (drawing_area),
"gtk-color-sel",
colorsel);
menu = gtk_menu_new ();
mi = gtk_menu_item_new_with_mnemonic (_("_Save color here"));
gtk_signal_connect (GTK_OBJECT (mi), "activate",
GTK_SIGNAL_FUNC (save_color_selected),
drawing_area);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
gtk_widget_show_all (mi);
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
popup_position_func, drawing_area,
3, timestamp);
}
static gint
palette_press (GtkWidget *drawing_area,
GdkEventButton *event,
gpointer data)
{
GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
gtk_widget_grab_focus (drawing_area);
if (event->button == 1 &&
event->type == GDK_BUTTON_PRESS)
{
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);
}
}
if (event->button == 3 &&
event->type == GDK_BUTTON_PRESS)
{
do_popup (colorsel, drawing_area, event->time);
}
return TRUE;
}
static void
palette_unset_color (GtkWidget *drawing_area)
{
if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (drawing_area), "color_set")) == 0)
return;
gtk_widget_reset_rc_styles (drawing_area);
gtk_object_set_data (GTK_OBJECT (drawing_area), "color_set", GINT_TO_POINTER (0));
}
static void
palette_drop_handle (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint time,
gpointer data)
{
guint16 *vals;
gdouble color[4];
if (selection_data->length < 0)
return;
if ((selection_data->format != 16) ||
(selection_data->length != 8))
{
g_warning ("Received invalid color data\n");
return;
}
vals = (guint16 *)selection_data->data;
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_change_color (widget, GTK_COLOR_SELECTION (data), color);
gtk_color_selection_set_color (GTK_COLOR_SELECTION (data), color);
}
static gint
palette_activate (GtkWidget *widget,
GdkEventKey *event,
gpointer data)
{
/* should have a drawing area subclass with an activate signal */
if ((event->keyval == GDK_space) ||
(event->keyval == GDK_Return) ||
(event->keyval == GDK_KP_Enter) ||
(event->keyval == GDK_KP_Space))
{
if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "color_set")) != 0)
{
gdouble color[4];
palette_get_color (widget, color);
gtk_color_selection_set_color (GTK_COLOR_SELECTION (data), color);
}
return TRUE;
}
return FALSE;
}
static gboolean
palette_popup (GtkWidget *widget,
gpointer data)
{
GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
do_popup (colorsel, widget, GDK_CURRENT_TIME);
return TRUE;
}
static GtkWidget*
palette_new (GtkColorSelection *colorsel)
{
GtkWidget *retval;
ColorSelectionPrivate *priv;
static const GtkTargetEntry targets[] = {
{ "application/x-color", 0 }
};
priv = colorsel->private_data;
retval = gtk_drawing_area_new ();
GTK_WIDGET_SET_FLAGS (retval, GTK_CAN_FOCUS);
gtk_object_set_data (GTK_OBJECT (retval), "color_set", GINT_TO_POINTER (0));
gtk_widget_set_events (retval, GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_EXPOSURE_MASK
| GDK_ENTER_NOTIFY_MASK
| GDK_LEAVE_NOTIFY_MASK);
gtk_signal_connect (GTK_OBJECT (retval), "expose_event",
GTK_SIGNAL_FUNC (palette_expose), colorsel);
gtk_signal_connect (GTK_OBJECT (retval), "button_press_event",
GTK_SIGNAL_FUNC (palette_press), colorsel);
gtk_signal_connect (GTK_OBJECT (retval), "key_press_event",
GTK_SIGNAL_FUNC (palette_activate), colorsel);
gtk_signal_connect (GTK_OBJECT (retval), "popup_menu",
GTK_SIGNAL_FUNC (palette_popup), 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",
GTK_SIGNAL_FUNC (palette_drag_end), NULL);
gtk_signal_connect (GTK_OBJECT (retval), "drag_data_received",
GTK_SIGNAL_FUNC (palette_drop_handle), colorsel);
gtk_tooltips_set_tip (priv->tooltips,
retval,
_("Click this palette entry to make it the current color. To change this entry, drag a color swatch here or right-click it and select \"Save color here.\""),
NULL);
return retval;
}
/*
*
* The actual GtkColorSelection widget
*
*/
static void
initialize_cursor (void)
{
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);
picker_cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, DROPPER_X_HOT ,DROPPER_Y_HOT);
gdk_pixmap_unref (pixmap);
gdk_pixmap_unref (mask);
}
static void
grab_color_at_mouse (GtkWidget *invisible,
gint x_root,
gint y_root,
gpointer data)
{
GdkImage *image;
guint32 pixel;
GtkColorSelection *colorsel = data;
ColorSelectionPrivate *priv;
GdkColormap *colormap = gdk_colormap_get_system ();
GdkColor color;
priv = colorsel->private_data;
image = gdk_image_get (GDK_ROOT_PARENT (), x_root, y_root, 1, 1);
pixel = gdk_image_get_pixel (image, 0, 0);
gdk_image_unref (image);
gdk_colormap_query_color (colormap, pixel, &color);
priv->color[COLORSEL_RED] = SCALE (color.red);
priv->color[COLORSEL_GREEN] = SCALE (color.green);
priv->color[COLORSEL_BLUE] = SCALE (color.blue);
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);
}
static void
shutdown_eyedropper (GtkWidget *widget)
{
GtkColorSelection *colorsel;
ColorSelectionPrivate *priv;
colorsel = GTK_COLOR_SELECTION (widget);
priv = colorsel->private_data;
gdk_keyboard_ungrab (gtk_get_current_event_time ());
gdk_pointer_ungrab (gtk_get_current_event_time ());
gtk_grab_remove (priv->dropper_grab_widget);
}
static void
mouse_motion (GtkWidget *invisible,
GdkEventMotion *event,
gpointer data)
{
grab_color_at_mouse (invisible, event->x_root, event->y_root, data);
}
static gboolean
mouse_release (GtkWidget *invisible,
GdkEventButton *event,
gpointer data)
{
GtkColorSelection *colorsel = data;
ColorSelectionPrivate *priv;
priv = colorsel->private_data;
if (event->button != 1)
return FALSE;
grab_color_at_mouse (invisible, event->x_root, event->y_root, data);
shutdown_eyedropper (GTK_WIDGET (data));
gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
GTK_SIGNAL_FUNC (mouse_motion), data);
gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
GTK_SIGNAL_FUNC (mouse_release), data);
return TRUE;
}
/* Helper Functions */
static gboolean mouse_press (GtkWidget *invisible,
GdkEventButton *event,
gpointer data);
static gboolean
key_press (GtkWidget *invisible,
GdkEventKey *event,
gpointer data)
{
if (event->keyval == GDK_Escape)
{
shutdown_eyedropper (data);
gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
GTK_SIGNAL_FUNC (mouse_press),
data);
gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
GTK_SIGNAL_FUNC (key_press),
data);
return TRUE;
}
return FALSE;
}
static gboolean
mouse_press (GtkWidget *invisible,
GdkEventButton *event,
gpointer data)
{
GtkColorSelection *colorsel = data;
ColorSelectionPrivate *priv;
priv = colorsel->private_data;
if (event->type == GDK_BUTTON_PRESS &&
event->button == 1)
{
gtk_signal_connect (GTK_OBJECT (invisible), "motion_notify_event",
GTK_SIGNAL_FUNC (mouse_motion),
data);
gtk_signal_connect (GTK_OBJECT (invisible), "button_release_event",
GTK_SIGNAL_FUNC (mouse_release),
data);
gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
GTK_SIGNAL_FUNC (mouse_press),
data);
gtk_signal_disconnect_by_func (GTK_OBJECT (invisible),
GTK_SIGNAL_FUNC (key_press),
data);
return TRUE;
}
return FALSE;
}
/* when the button is clicked */
static void
get_screen_color (GtkWidget *button)
{
GtkColorSelection *colorsel = gtk_object_get_data (GTK_OBJECT (button), "COLORSEL");
ColorSelectionPrivate *priv = colorsel->private_data;
if (picker_cursor == NULL)
{
initialize_cursor ();
}
if (priv->dropper_grab_widget == NULL)
{
priv->dropper_grab_widget = gtk_invisible_new ();
gtk_widget_add_events (priv->dropper_grab_widget,
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
gtk_widget_show (priv->dropper_grab_widget);
}
if (gdk_keyboard_grab (priv->dropper_grab_widget->window,
FALSE,
gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS)
{
g_warning ("Failed to grab keyboard to do eyedropper");
return;
}
if (gdk_pointer_grab (priv->dropper_grab_widget->window,
FALSE,
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK,
NULL,
picker_cursor,
gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS)
{
gdk_keyboard_ungrab (GDK_CURRENT_TIME);
g_warning ("Failed to grab pointer to do eyedropper");
return;
}
gtk_grab_add (priv->dropper_grab_widget);
gtk_signal_connect (GTK_OBJECT (priv->dropper_grab_widget), "button_press_event",
GTK_SIGNAL_FUNC (mouse_press), colorsel);
gtk_signal_connect (GTK_OBJECT (priv->dropper_grab_widget), "key_press_event",
GTK_SIGNAL_FUNC (key_press), colorsel);
}
static void
hex_changed (GtkWidget *hex_entry,
gpointer data)
{
GtkColorSelection *colorsel;
ColorSelectionPrivate *priv;
GdkColor color;
gchar *text;
colorsel = GTK_COLOR_SELECTION (data);
priv = colorsel->private_data;
if (priv->changing)
return;
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 void
hsv_changed (GtkWidget *hsv,
gpointer data)
{
GtkColorSelection *colorsel;
ColorSelectionPrivate *priv;
colorsel = GTK_COLOR_SELECTION (data);
priv = colorsel->private_data;
if (priv->changing)
return;
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 void
adjustment_changed (GtkAdjustment *adjustment,
gpointer data)
{
GtkColorSelection *colorsel;
ColorSelectionPrivate *priv;
colorsel = GTK_COLOR_SELECTION (gtk_object_get_data (GTK_OBJECT (adjustment), "COLORSEL"));
priv = colorsel->private_data;
if (priv->changing)
return;
switch (GPOINTER_TO_INT (data))
{
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 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 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;
}
update_color (colorsel);
}
static void
opacity_entry_changed (GtkWidget *opacity_entry,
gpointer data)
{
GtkColorSelection *colorsel;
ColorSelectionPrivate *priv;
GtkAdjustment *adj;
gchar *text;
colorsel = GTK_COLOR_SELECTION (data);
priv = colorsel->private_data;
if (priv->changing)
return;
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));
update_color (colorsel);
g_free (text);
}
static void
make_label_spinbutton (GtkColorSelection *colorsel,
GtkWidget **spinbutton,
gchar *text,
GtkWidget *table,
gint i,
gint j,
gint channel_type,
const gchar *tooltip)
{
GtkWidget *label;
GtkAdjustment *adjust;
ColorSelectionPrivate *priv = colorsel->private_data;
if (channel_type == COLORSEL_HUE)
{
adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 360.0, 1.0, 1.0, 1.0));
}
else
{
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_tooltips_set_tip (priv->tooltips, *spinbutton, tooltip, NULL);
gtk_signal_connect (GTK_OBJECT (adjust), "value_changed",
GTK_SIGNAL_FUNC (adjustment_changed),
GINT_TO_POINTER (channel_type));
label = gtk_label_new_with_mnemonic (text);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), *spinbutton);
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);
}
static void
make_palette_frame (GtkColorSelection *colorsel,
GtkWidget *table,
gint i,
gint j)
{
GtkWidget *frame;
ColorSelectionPrivate *priv;
priv = colorsel->private_data;
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);
}
/* Set the palette entry [x][y] to be the currently selected one. */
static void
set_selected_palette (GtkColorSelection *colorsel, int x, int y)
{
ColorSelectionPrivate *priv = colorsel->private_data;
gtk_widget_grab_focus (priv->custom_palette[x][y]);
}
static double
scale_round (double val, double factor)
{
val = floor (val * factor + 0.5);
val = MAX (val, 0);
val = MIN (val, factor);
return val;
}
static void
update_color (GtkColorSelection *colorsel)
{
ColorSelectionPrivate *priv = colorsel->private_data;
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)),
scale_round (priv->color[COLORSEL_HUE], 360));
gtk_adjustment_set_value (gtk_spin_button_get_adjustment
(GTK_SPIN_BUTTON (priv->sat_spinbutton)),
scale_round (priv->color[COLORSEL_SATURATION], 255));
gtk_adjustment_set_value (gtk_spin_button_get_adjustment
(GTK_SPIN_BUTTON (priv->val_spinbutton)),
scale_round (priv->color[COLORSEL_VALUE], 255));
gtk_adjustment_set_value (gtk_spin_button_get_adjustment
(GTK_SPIN_BUTTON (priv->red_spinbutton)),
scale_round (priv->color[COLORSEL_RED], 255));
gtk_adjustment_set_value (gtk_spin_button_get_adjustment
(GTK_SPIN_BUTTON (priv->green_spinbutton)),
scale_round (priv->color[COLORSEL_GREEN], 255));
gtk_adjustment_set_value (gtk_spin_button_get_adjustment
(GTK_SPIN_BUTTON (priv->blue_spinbutton)),
scale_round (priv->color[COLORSEL_BLUE], 255));
gtk_adjustment_set_value (gtk_range_get_adjustment
(GTK_RANGE (priv->opacity_slider)),
scale_round (priv->color[COLORSEL_OPACITY], 255));
g_snprintf (opacity_text, 32, "%.0f", scale_round (priv->color[COLORSEL_OPACITY], 255));
gtk_entry_set_text (GTK_ENTRY (priv->opacity_entry), opacity_text);
g_snprintf (entryval, 11, "#%2X%2X%2X",
(guint) (scale_round (priv->color[COLORSEL_RED], 255)),
(guint) (scale_round (priv->color[COLORSEL_GREEN], 255)),
(guint) (scale_round (priv->color[COLORSEL_BLUE], 255)));
for (ptr = entryval; *ptr; ptr++)
if (*ptr == ' ')
*ptr = '0';
gtk_entry_set_text (GTK_ENTRY (priv->hex_entry), entryval);
priv->changing = FALSE;
g_object_freeze_notify (G_OBJECT (colorsel));
g_object_notify (G_OBJECT (colorsel), "current_color");
g_object_notify (G_OBJECT (colorsel), "current_alpha");
g_object_thaw_notify (G_OBJECT (colorsel));
}
static void
fill_palette_from_string (const gchar *str)
{
GdkColor *colors = NULL;
gint n_colors = 0;
if (str == NULL)
return;
if (!gtk_color_selection_palette_from_string (str, &colors, &n_colors))
return;
if (n_colors > (GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT))
n_colors = GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT;
memcpy (current_colors, colors, sizeof (GdkColor) * n_colors);
g_free (colors);
}
static void
palette_change_notify_class (GObject *object,
GParamSpec *pspec)
{
gchar *str = NULL;
g_object_get (object, pspec->name, &str, NULL);
fill_palette_from_string (str);
g_free (str);
}
static void
update_palette (GtkColorSelection *colorsel)
{
gint i, j;
for (i = 0; i < GTK_CUSTOM_PALETTE_HEIGHT; i++)
{
for (j = 0; j < GTK_CUSTOM_PALETTE_WIDTH; j++)
{
gint index;
index = i * GTK_CUSTOM_PALETTE_WIDTH + j;
gtk_color_selection_set_palette_color (colorsel,
index,
&current_colors[index]);
}
}
}
static void
palette_change_notify_instance (GObject *object,
GParamSpec *pspec,
gpointer data)
{
update_palette (GTK_COLOR_SELECTION (data));
}
static void
default_change_palette_func (const GdkColor *colors,
gint n_colors)
{
gchar *str;
str = gtk_color_selection_palette_to_string (colors, n_colors);
gtk_settings_set_string_property (gtk_settings_get_default (),
"gtk-color-palette",
str,
"gtk_color_selection_palette_to_string");
g_free (str);
}
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,
};
color_selection_type = gtk_type_unique (GTK_TYPE_VBOX, &color_selection_info);
}
return color_selection_type;
}
static void
gtk_color_selection_class_init (GtkColorSelectionClass *klass)
{
GtkObjectClass *object_class;
GObjectClass *gobject_class;
GtkWidgetClass *widget_class;
object_class = GTK_OBJECT_CLASS (klass);
gobject_class = G_OBJECT_CLASS (klass);
widget_class = GTK_WIDGET_CLASS (klass);
parent_class = gtk_type_class (GTK_TYPE_VBOX);
object_class->destroy = gtk_color_selection_destroy;
gobject_class->finalize = gtk_color_selection_finalize;
gobject_class->set_property = gtk_color_selection_set_property;
gobject_class->get_property = gtk_color_selection_get_property;
widget_class->realize = gtk_color_selection_realize;
g_object_class_install_property (gobject_class,
PROP_HAS_OPACITY_CONTROL,
g_param_spec_boolean ("has_opacity_control",
_("Has Opacity Control"),
_("Whether the color selector should allow setting opacity"),
FALSE,
G_PARAM_READABLE | G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class,
PROP_HAS_PALETTE,
g_param_spec_boolean ("has_palette",
_("Has palette"),
_("Whether a palette should be used"),
FALSE,
G_PARAM_READABLE | G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class,
PROP_CURRENT_COLOR,
g_param_spec_boxed ("current_color",
_("Current Color"),
_("The current color"),
GDK_TYPE_COLOR,
G_PARAM_READABLE | G_PARAM_WRITABLE));
g_object_class_install_property (gobject_class,
PROP_CURRENT_ALPHA,
g_param_spec_uint ("current_alpha",
_("Current Alpha"),
_("The current opacity value (0 fully transparent, 65535 fully opaque)"),
0, 65535, 65535,
G_PARAM_READABLE | G_PARAM_WRITABLE));
color_selection_signals[COLOR_CHANGED] =
gtk_signal_new ("color_changed",
GTK_RUN_FIRST,
GTK_CLASS_TYPE (object_class),
GTK_SIGNAL_OFFSET (GtkColorSelectionClass, color_changed),
_gtk_marshal_VOID__VOID,
GTK_TYPE_NONE, 0);
gtk_settings_install_property (g_param_spec_string ("gtk-color-palette",
_("Custom palette"),
_("Palette to use in the color selector"),
default_colors,
G_PARAM_READWRITE));
}
/* 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;
gtk_widget_push_composite_child ();
priv = colorsel->private_data = g_new0 (ColorSelectionPrivate, 1);
priv->changing = FALSE;
priv->default_set = FALSE;
priv->default_alpha_set = FALSE;
priv->tooltips = gtk_tooltips_new ();
g_object_ref (priv->tooltips);
gtk_object_sink (GTK_OBJECT (priv->tooltips));
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",
GTK_SIGNAL_FUNC (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);
gtk_tooltips_set_tip (priv->tooltips, priv->triangle_colorsel,
_("Select the color you want from the outer ring. Select the darkness or lightness of that color using the inner triangle."), NULL);
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_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",
GTK_SIGNAL_FUNC (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);
gdk_pixmap_unref (dropper_pixmap);
if (mask)
gdk_pixmap_unref (mask);
gtk_container_add (GTK_CONTAINER (button), dropper_image);
gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_tooltips_set_tip (priv->tooltips,
button,
_("Click the eyedropper, then click a color anywhere on your screen to select that color."), NULL);
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,
_("Position on the color wheel."));
make_label_spinbutton (colorsel, &priv->sat_spinbutton, _("_Saturation:"), table, 0, 1, COLORSEL_SATURATION,
_("\"Deepness\" of the color."));
make_label_spinbutton (colorsel, &priv->val_spinbutton, _("_Value:"), table, 0, 2, COLORSEL_VALUE,
_("Brightness of the color."));
make_label_spinbutton (colorsel, &priv->red_spinbutton, _("_Red:"), table, 6, 0, COLORSEL_RED,
_("Amount of red light in the color."));
make_label_spinbutton (colorsel, &priv->green_spinbutton, _("_Green:"), table, 6, 1, COLORSEL_GREEN,
_("Amount of green light in the color."));
make_label_spinbutton (colorsel, &priv->blue_spinbutton, _("_Blue:"), table, 6, 2, COLORSEL_BLUE,
_("Amount of blue light in the color."));
gtk_table_attach_defaults (GTK_TABLE (table), gtk_hseparator_new (), 0, 8, 3, 4);
priv->opacity_label = gtk_label_new_with_mnemonic (_("_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_tooltips_set_tip (priv->tooltips,
priv->opacity_slider,
_("Transparency of the currently-selected color."), NULL);
gtk_label_set_mnemonic_widget (GTK_LABEL (priv->opacity_label),
priv->opacity_slider);
gtk_scale_set_draw_value (GTK_SCALE (priv->opacity_slider), FALSE);
gtk_signal_connect (GTK_OBJECT (adjust), "value_changed",
GTK_SIGNAL_FUNC (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), "activate",
GTK_SIGNAL_FUNC (opacity_entry_changed), colorsel);
gtk_table_attach_defaults (GTK_TABLE (table), priv->opacity_entry, 7, 8, 4, 5);
label = gtk_label_new_with_mnemonic (_("Color _Name:"));
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_label_set_mnemonic_widget (GTK_LABEL (label), priv->hex_entry);
gtk_signal_connect (GTK_OBJECT (priv->hex_entry), "activate",
GTK_SIGNAL_FUNC (hex_changed), colorsel);
gtk_tooltips_set_tip (priv->tooltips,
priv->hex_entry,
_("You can enter an HTML-style hexadecimal color value, or simply a color name such as 'orange' in this entry."), NULL);
gtk_widget_set_usize (priv->hex_entry, 75, -1);
gtk_table_set_col_spacing (GTK_TABLE (table), 3, 15);
gtk_table_attach_defaults (GTK_TABLE (table), priv->hex_entry, 1, 5, 5, 6);
/* Set up the palette */
table = gtk_table_new (GTK_CUSTOM_PALETTE_HEIGHT, GTK_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 < GTK_CUSTOM_PALETTE_WIDTH; i++)
{
for (j = 0; j < GTK_CUSTOM_PALETTE_HEIGHT; j++)
{
make_palette_frame (colorsel, table, i, j);
}
}
set_selected_palette (colorsel, 0, 0);
priv->palette_frame = gtk_frame_new (NULL);
label = gtk_label_new_with_mnemonic (_("_Palette"));
gtk_frame_set_label_widget (GTK_FRAME (priv->palette_frame), label);
gtk_label_set_mnemonic_widget (GTK_LABEL (label),
priv->custom_palette[0][0]);
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);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
gtk_widget_show_all (top_hbox);
/* hide unused stuff */
if (priv->has_opacity == FALSE)
{
gtk_widget_hide (priv->opacity_label);
gtk_widget_hide (priv->opacity_slider);
gtk_widget_hide (priv->opacity_entry);
}
if (priv->has_palette == FALSE)
{
gtk_widget_hide (priv->palette_frame);
}
gtk_widget_pop_composite_child ();
}
static void
gtk_color_selection_destroy (GtkObject *object)
{
GtkColorSelection *cselection = GTK_COLOR_SELECTION (object);
ColorSelectionPrivate *priv = cselection->private_data;
if (priv->dropper_grab_widget)
{
gtk_widget_destroy (priv->dropper_grab_widget);
priv->dropper_grab_widget = NULL;
}
if (priv->tooltips)
{
g_object_unref (priv->tooltips);
priv->tooltips = NULL;
}
GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
static void
gtk_color_selection_finalize (GObject *object)
{
GtkColorSelection *cselection = GTK_COLOR_SELECTION (object);
if (cselection->private_data)
{
ColorSelectionPrivate *priv;
priv = cselection->private_data;
g_signal_handler_disconnect (gtk_settings_get_default (),
priv->settings_connection);
g_free (cselection->private_data);
cselection->private_data = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gtk_color_selection_realize (GtkWidget *widget)
{
GtkColorSelection *colorsel = GTK_COLOR_SELECTION (widget);
ColorSelectionPrivate *priv = colorsel->private_data;
gchar *palette;
static gboolean initialized = FALSE;
if (!initialized)
{
g_object_get (gtk_settings_get_default (),
"gtk-color-palette", &palette,
NULL);
fill_palette_from_string (palette);
g_free (palette);
g_signal_connect (gtk_settings_get_default (),
"notify::gtk-color-palette",
G_CALLBACK (palette_change_notify_class),
NULL);
initialized = TRUE;
}
/* Set default colors */
update_palette (colorsel);
priv->settings_connection =
g_signal_connect (gtk_settings_get_default (),
"notify::gtk-color-palette",
G_CALLBACK (palette_change_notify_instance),
colorsel);
if (GTK_WIDGET_CLASS (parent_class)->realize)
GTK_WIDGET_CLASS (parent_class)->realize (widget);
}
/**
* gtk_color_selection_new:
*
* Creates a new GtkColorSelection.
*
* Return value: a new #GtkColorSelection
**/
GtkWidget *
gtk_color_selection_new (void)
{
GtkColorSelection *colorsel;
ColorSelectionPrivate *priv;
gdouble color[4];
color[0] = 1.0;
color[1] = 1.0;
color[2] = 1.0;
color[3] = 1.0;
colorsel = gtk_type_new (GTK_TYPE_COLOR_SELECTION);
priv = colorsel->private_data;
gtk_color_selection_set_color (colorsel, color);
gtk_color_selection_set_has_opacity_control (colorsel, TRUE);
/* We want to make sure that default_set is FALSE */
/* This way the user can still set it */
priv->default_set = FALSE;
priv->default_alpha_set = FALSE;
return GTK_WIDGET (colorsel);
}
void
gtk_color_selection_set_update_policy (GtkColorSelection *colorsel,
GtkUpdateType policy)
{
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
}
/**
* gtk_color_selection_get_has_opacity_control:
* @colorsel: a #GtkColorSelection.
*
* Determines whether the colorsel has an opacity control.
*
* Return value: %TRUE if the @colorsel has an opacity control. %FALSE if it does't.
**/
gboolean
gtk_color_selection_get_has_opacity_control (GtkColorSelection *colorsel)
{
ColorSelectionPrivate *priv;
g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE);
priv = colorsel->private_data;
return priv->has_opacity;
}
/**
* gtk_color_selection_set_has_opacity_control:
* @colorsel: a #GtkColorSelection.
* @has_opacity: %TRUE if @colorsel can set the opacity, %FALSE otherwise.
*
* Sets the @colorsel to use or not use opacity.
*
**/
void
gtk_color_selection_set_has_opacity_control (GtkColorSelection *colorsel,
gboolean has_opacity)
{
ColorSelectionPrivate *priv;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
priv = colorsel->private_data;
has_opacity = has_opacity != FALSE;
if (priv->has_opacity != has_opacity)
{
priv->has_opacity = has_opacity;
if (has_opacity)
{
gtk_widget_show (priv->opacity_slider);
gtk_widget_show (priv->opacity_label);
gtk_widget_show (priv->opacity_entry);
}
else
{
gtk_widget_hide (priv->opacity_slider);
gtk_widget_hide (priv->opacity_label);
gtk_widget_hide (priv->opacity_entry);
}
color_sample_draw_samples (colorsel);
g_object_notify (G_OBJECT (colorsel), "has_opacity_control");
}
}
/**
* gtk_color_selection_get_has_palette:
* @colorsel: a #GtkColorSelection.
*
* Determines whether the color selector has a color palette.
*
* Return value: %TRUE if the selector has a palette. %FALSE if it hasn't.
**/
gboolean
gtk_color_selection_get_has_palette (GtkColorSelection *colorsel)
{
ColorSelectionPrivate *priv;
g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE);
priv = colorsel->private_data;
return priv->has_palette;
}
/**
* gtk_color_selection_set_has_palette:
* @colorsel: a #GtkColorSelection.
* @has_palette: %TRUE if palette is to be visible, %FALSE otherwise.
*
* Shows and hides the palette based upon the value of @has_palette.
*
**/
void
gtk_color_selection_set_has_palette (GtkColorSelection *colorsel,
gboolean has_palette)
{
ColorSelectionPrivate *priv;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
priv = colorsel->private_data;
has_palette = has_palette != FALSE;
if (priv->has_palette != has_palette)
{
priv->has_palette = has_palette;
if (has_palette)
gtk_widget_show (priv->palette_frame);
else
gtk_widget_hide (priv->palette_frame);
g_object_notify (G_OBJECT (colorsel), "has_palette");
}
}
/**
* gtk_color_selection_set_current_color:
* @colorsel: a #GtkColorSelection.
* @color: A #GdkColor 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_current_color (GtkColorSelection *colorsel,
GdkColor *color)
{
ColorSelectionPrivate *priv;
gint i;
gboolean previous_changed;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
priv = colorsel->private_data;
priv->changing = TRUE;
priv->color[COLORSEL_RED] = SCALE (color->red);
priv->color[COLORSEL_GREEN] = SCALE (color->green);
priv->color[COLORSEL_BLUE] = SCALE (color->blue);
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)
{
previous_changed = TRUE;
for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
priv->old_color[i] = priv->color[i];
}
update_color (colorsel);
priv->default_set = TRUE;
}
/**
* gtk_color_selection_set_current_alpha:
* @colorsel: a #GtkColorSelection.
* @alpha: an integer between 0 and 65535.
*
* Sets the current opacity to be @alpha. The first time this is called, it will
* also set the original opacity to be @alpha too.
**/
void
gtk_color_selection_set_current_alpha (GtkColorSelection *colorsel,
guint16 alpha)
{
ColorSelectionPrivate *priv;
gint i;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
priv = colorsel->private_data;
priv->changing = TRUE;
priv->color[COLORSEL_OPACITY] = SCALE (alpha);
if (priv->default_alpha_set == FALSE)
{
for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
priv->old_color[i] = priv->color[i];
}
update_color (colorsel);
priv->default_alpha_set = TRUE;
}
/**
* gtk_color_selection_set_color:
* @colorsel: a #GtkColorSelection.
* @color: an array of 4 doubles specifying the red, green, blue and opacity
* to set the current color to.
*
* Sets the current color to be @color. The first time this is called, it will
* also set the original color to be @color too.
*
* This function is deprecated, use gtk_color_selection_set_current_color() instead.
**/
void
gtk_color_selection_set_color (GtkColorSelection *colorsel,
gdouble *color)
{
ColorSelectionPrivate *priv;
gint i;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
priv = colorsel->private_data;
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;
priv->default_alpha_set = TRUE;
}
/**
* gtk_color_selection_get_current_color:
* @colorsel: a #GtkColorSelection.
* @color: a #GdkColor to fill in with the current color.
*
* Sets @color to be the current color in the GtkColorSelection widget.
**/
void
gtk_color_selection_get_current_color (GtkColorSelection *colorsel,
GdkColor *color)
{
ColorSelectionPrivate *priv;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
priv = colorsel->private_data;
color->red = UNSCALE (priv->color[COLORSEL_RED]);
color->green = UNSCALE (priv->color[COLORSEL_GREEN]);
color->blue = UNSCALE (priv->color[COLORSEL_BLUE]);
}
/**
* gtk_color_selection_get_current_alpha:
* @colorsel: a #GtkColorSelection.
*
* Returns the current alpha value.
*
* Return value: an integer between 0 and 65535.
**/
guint16
gtk_color_selection_get_current_alpha (GtkColorSelection *colorsel)
{
ColorSelectionPrivate *priv;
g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), 0);
priv = colorsel->private_data;
return priv->has_opacity ? UNSCALE (priv->color[COLORSEL_OPACITY]) : 65535;
}
/**
* gtk_color_selection_get_color:
* @colorsel: a #GtkColorSelection.
* @color: an array of 4 #gdouble to fill in with the current color.
*
* Sets @color to be the current color in the GtkColorSelection widget.
*
* This function is deprecated, use gtk_color_selection_get_current_color() instead.
**/
void
gtk_color_selection_get_color (GtkColorSelection *colorsel,
gdouble *color)
{
ColorSelectionPrivate *priv;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
priv = colorsel->private_data;
color[0] = priv->color[COLORSEL_RED];
color[1] = priv->color[COLORSEL_GREEN];
color[2] = priv->color[COLORSEL_BLUE];
color[3] = priv->has_opacity ? priv->color[COLORSEL_OPACITY] : 65535;
}
/**
* gtk_color_selection_set_previous_color:
* @colorsel: a #GtkColorSelection.
* @color: a #GdkColor to set the previous color with.
*
* Sets the 'previous' 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_current_color() will also set this color the first
* time it is called.
**/
void
gtk_color_selection_set_previous_color (GtkColorSelection *colorsel,
GdkColor *color)
{
ColorSelectionPrivate *priv;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
priv = colorsel->private_data;
priv->changing = TRUE;
priv->old_color[COLORSEL_RED] = SCALE (color->red);
priv->old_color[COLORSEL_GREEN] = SCALE (color->green);
priv->old_color[COLORSEL_BLUE] = SCALE (color->blue);
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_set_previous_alpha:
* @colorsel: a #GtkColorSelection.
* @alpha: an integer between 0 and 65535.
*
* Sets the 'previous' alpha to be @alpha. This function should be called with
* some hesitations, as it might seem confusing to have that alpha change.
**/
void
gtk_color_selection_set_previous_alpha (GtkColorSelection *colorsel,
guint16 alpha)
{
ColorSelectionPrivate *priv;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
priv = colorsel->private_data;
priv->changing = TRUE;
priv->old_color[COLORSEL_OPACITY] = SCALE (alpha);
color_sample_draw_samples (colorsel);
priv->default_alpha_set = TRUE;
}
/**
* gtk_color_selection_get_previous_color:
* @colorsel: a #GtkColorSelection.
* @color: a #GdkColor to fill in with the original color value.
*
* Fills @color in with the original color value.
**/
void
gtk_color_selection_get_previous_color (GtkColorSelection *colorsel,
GdkColor *color)
{
ColorSelectionPrivate *priv;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
priv = colorsel->private_data;
color->red = UNSCALE (priv->old_color[COLORSEL_RED]);
color->green = UNSCALE (priv->old_color[COLORSEL_GREEN]);
color->blue = UNSCALE (priv->old_color[COLORSEL_BLUE]);
}
/**
* gtk_color_selection_get_previous_alpha:
* @colorsel: a #GtkColorSelection.
*
* Returns the previous alpha value.
*
* Return value: an integer between 0 and 65535.
**/
guint16
gtk_color_selection_get_previous_alpha (GtkColorSelection *colorsel)
{
ColorSelectionPrivate *priv;
g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), 0);
priv = colorsel->private_data;
return priv->has_opacity ? UNSCALE (priv->old_color[COLORSEL_OPACITY]) : 65535;
}
/**
* gtk_color_selection_set_palette_color:
* @colorsel: a #GtkColorSelection.
* @index: the color index of the palette.
* @color: A #GdkColor to set the palette with.
*
* Sets the palette located at @index to have @color as its color.
*
**/
static void
gtk_color_selection_set_palette_color (GtkColorSelection *colorsel,
gint index,
GdkColor *color)
{
ColorSelectionPrivate *priv;
gint x, y;
gdouble col[3];
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
g_return_if_fail (index >= 0 && index < GTK_CUSTOM_PALETTE_WIDTH*GTK_CUSTOM_PALETTE_HEIGHT);
x = index % GTK_CUSTOM_PALETTE_WIDTH;
y = index / GTK_CUSTOM_PALETTE_WIDTH;
priv = colorsel->private_data;
col[0] = SCALE (color->red);
col[1] = SCALE (color->green);
col[2] = SCALE (color->blue);
palette_set_color (priv->custom_palette[x][y], colorsel, col);
}
/**
* gtk_color_selection_get_palette_color:
* @colorsel: a #GtkColorSelection.
* @index: the color index of the palette.
* @color: a #GdkColor to fill in with the color value.
*
* Set @color to have the color found in the palette at @index. If
* the palette is unset, it will leave the color unset.
*
* Return value: %TRUE if the palette located at @index has a color set. %FALSE
* if it doesn't.
**/
static gboolean
gtk_color_selection_get_palette_color (GtkColorSelection *colorsel,
gint index,
GdkColor *color)
{
ColorSelectionPrivate *priv;
gint x, y;
gdouble col[4];
g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE);
g_return_val_if_fail (index >= 0 && index < GTK_CUSTOM_PALETTE_WIDTH*GTK_CUSTOM_PALETTE_HEIGHT, FALSE);
priv = colorsel->private_data;
x = index % GTK_CUSTOM_PALETTE_WIDTH;
y = index / GTK_CUSTOM_PALETTE_WIDTH;
if (GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (priv->custom_palette[x][y]), "color_set")) == 0)
return FALSE;
palette_get_color (priv->custom_palette[x][y], col);
color->red = UNSCALE (col[0]);
color->green = UNSCALE (col[1]);
color->blue = UNSCALE (col[2]);
return TRUE;
}
/**
* gtk_color_selection_unset_palette_color:
* @colorsel: a #GtkColorSelection.
* @index: the color index in the palette.
*
* Changes the palette located @index to have no color set.
**/
static void
gtk_color_selection_unset_palette_color (GtkColorSelection *colorsel,
gint index)
{
ColorSelectionPrivate *priv;
gint x, y;
g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
g_return_if_fail (index >= 0 && index < GTK_CUSTOM_PALETTE_WIDTH*GTK_CUSTOM_PALETTE_HEIGHT);
x = index % GTK_CUSTOM_PALETTE_WIDTH;
y = index / GTK_CUSTOM_PALETTE_WIDTH;
priv = colorsel->private_data;
palette_unset_color (priv->custom_palette[x][y]);
}
/**
* gtk_color_selection_get_current_alpha:
* @colorsel: a #GtkColorSelection.
*
* Returns the maximum number of palette colors.
*
* Return value: the maximum number of palette indexes.
**/
static gint
gtk_color_selection_get_palette_size (GtkColorSelection *colorsel)
{
return GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT;
}
/**
* 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 (GTK_IS_COLOR_SELECTION (colorsel), FALSE);
priv = colorsel->private_data;
return (gtk_hsv_is_adjusting (GTK_HSV (priv->triangle_colorsel)));
}
static void
gtk_color_selection_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColorSelection *colorsel = GTK_COLOR_SELECTION (object);
switch (prop_id)
{
case PROP_HAS_OPACITY_CONTROL:
gtk_color_selection_set_has_opacity_control (colorsel,
g_value_get_boolean (value));
break;
case PROP_HAS_PALETTE:
gtk_color_selection_set_has_palette (colorsel,
g_value_get_boolean (value));
break;
case PROP_CURRENT_COLOR:
gtk_color_selection_set_current_color (colorsel, g_value_get_boxed (value));
break;
case PROP_CURRENT_ALPHA:
gtk_color_selection_set_current_alpha (colorsel, g_value_get_uint (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_color_selection_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkColorSelection *colorsel = GTK_COLOR_SELECTION (object);
GdkColor color;
switch (prop_id)
{
case PROP_HAS_OPACITY_CONTROL:
g_value_set_boolean (value, gtk_color_selection_get_has_opacity_control (colorsel));
break;
case PROP_HAS_PALETTE:
g_value_set_boolean (value, gtk_color_selection_get_has_palette (colorsel));
break;
case PROP_CURRENT_COLOR:
gtk_color_selection_get_current_color (colorsel, &color);
g_value_set_boxed (value, &color);
break;
case PROP_CURRENT_ALPHA:
g_value_set_uint (value, gtk_color_selection_get_current_alpha (colorsel));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* gtk_color_selection_palette_from_string:
* @str: a string encoding a color palette.
* @colors: return location for allocated array of #GdkColor.
* @n_colors: return location for length of array.
*
* Parses a color palette string; the string is a colon-separated
* list of color names readable by gdk_color_parse().
*
* Return value: %TRUE if a palette was successfully parsed.
**/
gboolean
gtk_color_selection_palette_from_string (const gchar *str,
GdkColor **colors,
gint *n_colors)
{
GdkColor *retval;
gint count;
gchar *p;
gchar *start;
gchar *copy;
count = 0;
retval = NULL;
copy = g_strdup (str);
start = copy;
p = copy;
while (TRUE)
{
if (*p == ':' || *p == '\0')
{
gboolean done = TRUE;
if (start == p)
{
goto failed; /* empty entry */
}
if (*p)
{
*p = '\0';
done = FALSE;
}
retval = g_renew (GdkColor, retval, count + 1);
if (!gdk_color_parse (start, retval + count))
{
goto failed;
}
++count;
if (done)
break;
else
start = p + 1;
}
++p;
}
g_free (copy);
if (colors)
*colors = retval;
else
g_free (retval);
if (n_colors)
*n_colors = count;
return TRUE;
failed:
g_free (copy);
g_free (retval);
if (colors)
*colors = NULL;
if (n_colors)
*n_colors = 0;
return FALSE;
}
/**
* gtk_color_selection_palette_to_string:
* @colors: an array of colors.
* @n_colors: length of the array.
*
* Encodes a palette as a string, useful for persistent storage.
*
* Return value: allocated string encoding the palette.
**/
gchar*
gtk_color_selection_palette_to_string (const GdkColor *colors,
gint n_colors)
{
gint i;
gchar **strs = NULL;
gchar *retval;
if (n_colors == 0)
return g_strdup ("");
strs = g_new0 (gchar*, n_colors + 1);
i = 0;
while (i < n_colors)
{
gchar *ptr;
strs[i] =
g_strdup_printf ("#%2X%2X%2X",
colors[i].red / 256,
colors[i].green / 256,
colors[i].blue / 256);
for (ptr = strs[i]; *ptr; ptr++)
if (*ptr == ' ')
*ptr = '0';
++i;
}
retval = g_strjoinv (":", strs);
g_strfreev (strs);
return retval;
}
/**
* gtk_color_selection_set_change_palette_hook:
* @func: a function to call when the custom palette needs saving.
*
* Installs a global function to be called whenever the user tries to
* modify the palette in a color selection. This function should save
* the new palette contents, and update the GtkSettings property
* "gtk-color-palette" so all GtkColorSelection widgets will be modified.
*
* Return value: the previous change palette hook (that was replaced).
**/
GtkColorSelectionChangePaletteFunc
gtk_color_selection_set_change_palette_hook (GtkColorSelectionChangePaletteFunc func)
{
GtkColorSelectionChangePaletteFunc old;
old = change_palette_hook;
change_palette_hook = func;
return old;
}