gimp/libgimpwidgets/gimpcolorscale.c

924 lines
28 KiB
C

/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* gimpcolorscale.c
* Copyright (C) 2002-2010 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
*
* 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 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libgimpbase/gimpbase.h"
#include "libgimpconfig/gimpconfig.h"
#include "libgimpcolor/gimpcolor.h"
#include "gimpwidgetstypes.h"
#include "gimpcairo-utils.h"
#include "gimpcolorscale.h"
#include "gimpwidgetsutils.h"
/**
* SECTION: gimpcolorscale
* @title: GimpColorScale
* @short_description: Fancy colored sliders.
*
* Fancy colored sliders.
**/
enum
{
PROP_0,
PROP_CHANNEL
};
struct _GimpColorScale
{
GtkScale parent_instance;
GimpColorConfig *config;
guchar oog_color[3];
const Babl *format;
GimpColorSelectorChannel channel;
GeglColor *color;
guchar *buf;
guint width;
guint height;
guint rowstride;
gboolean needs_render;
};
static void gimp_color_scale_dispose (GObject *object);
static void gimp_color_scale_finalize (GObject *object);
static void gimp_color_scale_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_color_scale_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_color_scale_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean gimp_color_scale_draw (GtkWidget *widget,
cairo_t *cr);
static void gimp_color_scale_render (GimpColorScale *scale);
static void gimp_color_scale_render_alpha (GimpColorScale *scale);
static void gimp_color_scale_notify_config (GimpColorConfig *config,
const GParamSpec *pspec,
GimpColorScale *scale);
G_DEFINE_TYPE (GimpColorScale, gimp_color_scale, GTK_TYPE_SCALE)
#define parent_class gimp_color_scale_parent_class
static const Babl *fish_lch_to_rgb = NULL;
static const Babl *fish_hsv_to_rgb = NULL;
static const Babl *fish_rgb_to_cairo = NULL;
static void
gimp_color_scale_class_init (GimpColorScaleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = gimp_color_scale_dispose;
object_class->finalize = gimp_color_scale_finalize;
object_class->get_property = gimp_color_scale_get_property;
object_class->set_property = gimp_color_scale_set_property;
widget_class->size_allocate = gimp_color_scale_size_allocate;
widget_class->draw = gimp_color_scale_draw;
/**
* GimpColorScale:channel:
*
* The channel which is edited by the color scale.
*
* Since: 2.8
*/
g_object_class_install_property (object_class, PROP_CHANNEL,
g_param_spec_enum ("channel",
"Channel",
"The channel which is edited by the color scale",
GIMP_TYPE_COLOR_SELECTOR_CHANNEL,
GIMP_COLOR_SELECTOR_VALUE,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
gtk_widget_class_set_css_name (widget_class, "GimpColorScale");
fish_lch_to_rgb = babl_fish (babl_format ("CIE LCH(ab) float"),
babl_format ("R'G'B' double"));
fish_hsv_to_rgb = babl_fish (babl_format ("HSV float"),
babl_format ("R'G'B' double"));
fish_rgb_to_cairo = babl_fish (babl_format ("R'G'B' u8"),
babl_format ("cairo-RGB24"));
}
static void
gimp_color_scale_init (GimpColorScale *scale)
{
GtkRange *range = GTK_RANGE (scale);
GtkCssProvider *css;
gtk_widget_set_can_focus (GTK_WIDGET (scale), TRUE);
gtk_range_set_slider_size_fixed (range, TRUE);
gtk_range_set_flippable (GTK_RANGE (scale), TRUE);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
scale->channel = GIMP_COLOR_SELECTOR_VALUE;
scale->needs_render = TRUE;
gtk_orientable_set_orientation (GTK_ORIENTABLE (range),
GTK_ORIENTATION_HORIZONTAL);
scale->color = gegl_color_new ("black");
css = gtk_css_provider_new ();
gtk_css_provider_load_from_data (css,
"GimpColorScale {"
" padding: 2px 12px 2px 12px;"
" min-width: 24px;"
" min-height: 24px;"
"}\n"
"GimpColorScale contents trough {"
" min-width: 20px;"
" min-height: 20px;"
"}\n"
"GimpColorScale contents trough slider {"
" min-width: 12px;"
" min-height: 12px;"
" margin: -6px -6px -6px -6px;"
"}",
-1, NULL);
gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (scale)),
GTK_STYLE_PROVIDER (css),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref (css);
}
static void
gimp_color_scale_dispose (GObject *object)
{
GimpColorScale *scale = GIMP_COLOR_SCALE (object);
gimp_color_scale_set_color_config (scale, NULL);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gimp_color_scale_finalize (GObject *object)
{
GimpColorScale *scale = GIMP_COLOR_SCALE (object);
g_clear_pointer (&scale->buf, g_free);
scale->width = 0;
scale->height = 0;
scale->rowstride = 0;
g_object_unref (scale->color);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_color_scale_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpColorScale *scale = GIMP_COLOR_SCALE (object);
switch (property_id)
{
case PROP_CHANNEL:
g_value_set_enum (value, scale->channel);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_color_scale_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpColorScale *scale = GIMP_COLOR_SCALE (object);
switch (property_id)
{
case PROP_CHANNEL:
gimp_color_scale_set_channel (scale, g_value_get_enum (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_color_scale_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GimpColorScale *scale = GIMP_COLOR_SCALE (widget);
GtkRange *range = GTK_RANGE (widget);
GdkRectangle range_rect;
GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
gtk_range_get_range_rect (range, &range_rect);
if (range_rect.width != scale->width ||
range_rect.height != scale->height)
{
scale->width = range_rect.width;
scale->height = range_rect.height;
/* TODO: we should move to CAIRO_FORMAT_RGBA128F. */
scale->rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, scale->width);
g_free (scale->buf);
scale->buf = g_new (guchar, 3 * scale->width * scale->height);
scale->needs_render = TRUE;
}
}
static gboolean
gimp_color_scale_draw (GtkWidget *widget,
cairo_t *cr)
{
GimpColorScale *scale = GIMP_COLOR_SCALE (widget);
GtkRange *range = GTK_RANGE (widget);
GtkStyleContext *context = gtk_widget_get_style_context (widget);
GdkRectangle range_rect;
GdkRectangle area = { 0, };
cairo_surface_t *buffer;
guchar *buf = NULL;
guchar *src;
guchar *dest;
gint slider_start;
gint slider_end;
gint slider_mid;
gint slider_size;
const Babl *render_space;
if (! scale->buf)
return FALSE;
gtk_range_get_range_rect (range, &range_rect);
gtk_range_get_slider_range (range, &slider_start, &slider_end);
slider_mid = slider_start + (slider_end - slider_start) / 2;
slider_size = 6;
if (scale->needs_render)
{
gimp_color_scale_render (scale);
scale->needs_render = FALSE;
}
render_space = gimp_widget_get_render_space (widget, scale->config);
fish_rgb_to_cairo = babl_fish (babl_format_with_space ("R'G'B' u8", scale->format),
babl_format_with_space ("cairo-RGB24", render_space)),
src = scale->buf;
buf = g_new (guchar, scale->rowstride * scale->height);
dest = buf;
/* We convert per line because the cairo rowstride may be bigger than the
* real contents.
*/
for (gint i = 0; i < scale->height; i++)
{
babl_process (fish_rgb_to_cairo, src, dest, scale->width);
src += 3 * scale->width;
dest += scale->rowstride;
}
buffer = cairo_image_surface_create_for_data (buf,
CAIRO_FORMAT_RGB24,
scale->width,
scale->height,
scale->rowstride);
cairo_surface_set_user_data (buffer, NULL, buf, (cairo_destroy_func_t) g_free);
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
cairo_set_source_surface (cr, buffer,
range_rect.x, range_rect.y);
break;
case GTK_ORIENTATION_VERTICAL:
cairo_set_source_surface (cr, buffer,
range_rect.x, range_rect.y);
break;
}
cairo_surface_destroy (buffer);
if (! gtk_widget_is_sensitive (widget))
{
static cairo_pattern_t *pattern = NULL;
if (! pattern)
{
static const guchar stipple[] = { 0, 255, 0, 0,
255, 0, 0, 0 };
cairo_surface_t *surface;
gint stride;
stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, 2);
surface = cairo_image_surface_create_for_data ((guchar *) stipple,
CAIRO_FORMAT_A8,
2, 2, stride);
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
}
cairo_mask (cr, pattern);
}
else
{
cairo_paint (cr);
}
if (gtk_widget_has_focus (widget))
gtk_render_focus (context, cr,
0, 0,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
area.x = slider_mid - slider_size;
area.y = range_rect.y;
area.width = 2 * slider_size;
area.height = range_rect.height;
break;
case GTK_ORIENTATION_VERTICAL:
area.x = range_rect.x;
area.y = slider_mid - slider_size;
area.width = range_rect.width;
area.height = 2 * slider_size;
break;
}
if (gtk_widget_is_sensitive (widget))
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
else
cairo_set_source_rgb (cr, 0.2, 0.2, 0.2);
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
cairo_move_to (cr, area.x, area.y);
cairo_line_to (cr, area.x + area.width, area.y);
cairo_line_to (cr,
area.x + area.width / 2 + 0.5,
area.y + slider_size);
break;
case GTK_ORIENTATION_VERTICAL:
cairo_move_to (cr, area.x, area.y);
cairo_line_to (cr, area.x, area.y + area.height);
cairo_line_to (cr,
area.x + slider_size,
area.y + area.height / 2 + 0.5);
break;
}
cairo_close_path (cr);
cairo_fill (cr);
if (gtk_widget_is_sensitive (widget))
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
else
cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
cairo_move_to (cr, area.x, area.y + area.height);
cairo_line_to (cr, area.x + area.width, area.y + area.height);
cairo_line_to (cr,
area.x + area.width / 2 + 0.5,
area.y + area.height - slider_size);
break;
case GTK_ORIENTATION_VERTICAL:
cairo_move_to (cr, area.x + area.width, area.y);
cairo_line_to (cr, area.x + area.width, area.y + area.height);
cairo_line_to (cr,
area.x + area.width - slider_size,
area.y + area.height / 2 + 0.5);
break;
}
cairo_close_path (cr);
cairo_fill (cr);
return FALSE;
}
/**
* gimp_color_scale_new:
* @orientation: the scale's orientation (horizontal or vertical)
* @channel: the scale's color channel
*
* Creates a new #GimpColorScale widget.
*
* Returns: a new #GimpColorScale widget
**/
GtkWidget *
gimp_color_scale_new (GtkOrientation orientation,
GimpColorSelectorChannel channel)
{
GimpColorScale *scale = g_object_new (GIMP_TYPE_COLOR_SCALE,
"orientation", orientation,
"channel", channel,
NULL);
gtk_range_set_flippable (GTK_RANGE (scale),
orientation == GTK_ORIENTATION_HORIZONTAL);
return GTK_WIDGET (scale);
}
/**
* gimp_color_scale_set_format:
* @scale: a #GimpColorScale widget
* @format: the Babl format represented by @scale.
*
* Changes the color format displayed by the @scale.
**/
void
gimp_color_scale_set_format (GimpColorScale *scale,
const Babl *format)
{
if (scale->format != format)
{
scale->format = format;
fish_lch_to_rgb = babl_fish (babl_format ("CIE LCH(ab) float"),
babl_format_with_space ("R'G'B' double", format));
fish_hsv_to_rgb = babl_fish (babl_format_with_space ("HSV float", format),
babl_format_with_space ("R'G'B' double", format));
scale->needs_render = TRUE;
gtk_widget_queue_draw (GTK_WIDGET (scale));
}
}
/**
* gimp_color_scale_set_channel:
* @scale: a #GimpColorScale widget
* @channel: the new color channel
*
* Changes the color channel displayed by the @scale.
**/
void
gimp_color_scale_set_channel (GimpColorScale *scale,
GimpColorSelectorChannel channel)
{
g_return_if_fail (GIMP_IS_COLOR_SCALE (scale));
if (channel != scale->channel)
{
scale->channel = channel;
scale->needs_render = TRUE;
gtk_widget_queue_draw (GTK_WIDGET (scale));
g_object_notify (G_OBJECT (scale), "channel");
}
}
/**
* gimp_color_scale_set_color:
* @scale: a #GimpColorScale widget
* @color: the new color.
*
* Changes the color value of the @scale.
**/
void
gimp_color_scale_set_color (GimpColorScale *scale,
GeglColor *color)
{
GeglColor *old_color;
g_return_if_fail (GIMP_IS_COLOR_SCALE (scale));
g_return_if_fail (GEGL_IS_COLOR (color));
old_color = scale->color;
scale->color = gegl_color_duplicate (color);
if (! gimp_color_is_perceptually_identical (old_color, scale->color))
{
scale->needs_render = TRUE;
gtk_widget_queue_draw (GTK_WIDGET (scale));
}
g_object_unref (old_color);
}
/**
* gimp_color_scale_set_color_config:
* @scale: a #GimpColorScale widget.
* @config: a #GimpColorConfig object.
*
* Sets the color management configuration to use with this color scale.
*
* Since: 2.10
*/
void
gimp_color_scale_set_color_config (GimpColorScale *scale,
GimpColorConfig *config)
{
g_return_if_fail (GIMP_IS_COLOR_SCALE (scale));
g_return_if_fail (config == NULL || GIMP_IS_COLOR_CONFIG (config));
if (config != scale->config)
{
if (scale->config)
{
g_signal_handlers_disconnect_by_func (scale->config,
gimp_color_scale_notify_config,
scale);
}
g_set_object (&scale->config, config);
if (scale->config)
{
g_signal_connect (scale->config, "notify",
G_CALLBACK (gimp_color_scale_notify_config),
scale);
gimp_color_scale_notify_config (scale->config, NULL, scale);
}
}
}
/* as in gtkrange.c */
static gboolean
should_invert (GtkRange *range)
{
gboolean inverted = gtk_range_get_inverted (range);
gboolean flippable = gtk_range_get_flippable (range);
if (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) ==
GTK_ORIENTATION_HORIZONTAL)
{
return
(inverted && !flippable) ||
(inverted && flippable &&
gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_LTR) ||
(!inverted && flippable &&
gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL);
}
else
{
return inverted;
}
}
static void
gimp_color_scale_render (GimpColorScale *scale)
{
GtkRange *range = GTK_RANGE (scale);
gdouble rgb[4];
gfloat hsv[3];
gfloat lch[3];
gint multiplier = 1;
guint x, y;
gdouble *channel_value = NULL;
gfloat *channel_value_f = NULL;
gboolean from_hsv = FALSE;
gboolean from_lch = FALSE;
gboolean invert;
guchar *buf;
guchar *d;
if ((buf = scale->buf) == NULL)
return;
if (scale->channel == GIMP_COLOR_SELECTOR_ALPHA)
{
gimp_color_scale_render_alpha (scale);
return;
}
gegl_color_get_pixel (scale->color, babl_format_with_space ("R'G'B'A double", scale->format), rgb);
gegl_color_get_pixel (scale->color, babl_format_with_space ("HSV float", scale->format), hsv);
gegl_color_get_pixel (scale->color, babl_format ("CIE LCH(ab) float"), lch);
switch (scale->channel)
{
case GIMP_COLOR_SELECTOR_HUE: channel_value_f = &hsv[0]; break;
case GIMP_COLOR_SELECTOR_SATURATION: channel_value_f = &hsv[1]; break;
case GIMP_COLOR_SELECTOR_VALUE: channel_value_f = &hsv[2]; break;
case GIMP_COLOR_SELECTOR_RED: channel_value = &rgb[0]; break;
case GIMP_COLOR_SELECTOR_GREEN: channel_value = &rgb[1]; break;
case GIMP_COLOR_SELECTOR_BLUE: channel_value = &rgb[2]; break;
case GIMP_COLOR_SELECTOR_ALPHA: channel_value = &rgb[3]; break;
case GIMP_COLOR_SELECTOR_LCH_LIGHTNESS: channel_value_f = &lch[0]; break;
case GIMP_COLOR_SELECTOR_LCH_CHROMA: channel_value_f = &lch[1]; break;
case GIMP_COLOR_SELECTOR_LCH_HUE: channel_value_f = &lch[2]; break;
}
switch (scale->channel)
{
case GIMP_COLOR_SELECTOR_HUE:
case GIMP_COLOR_SELECTOR_SATURATION:
case GIMP_COLOR_SELECTOR_VALUE:
from_hsv = TRUE;
break;
case GIMP_COLOR_SELECTOR_LCH_LIGHTNESS:
multiplier = 100;
from_lch = TRUE;
break;
case GIMP_COLOR_SELECTOR_LCH_CHROMA:
multiplier = 200;
from_lch = TRUE;
break;
case GIMP_COLOR_SELECTOR_LCH_HUE:
multiplier = 360;
from_lch = TRUE;
break;
default:
break;
}
invert = should_invert (range);
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
for (x = 0, d = buf; x < scale->width; x++, d += 3)
{
gdouble value = (gdouble) x * multiplier / (gdouble) (scale->width - 1);
if (invert)
value = multiplier - value;
if (channel_value)
*channel_value = value;
else if (channel_value_f)
*channel_value_f = (gfloat) value;
if (from_hsv)
babl_process (fish_hsv_to_rgb, &hsv, &rgb, 1);
else if (from_lch)
babl_process (fish_lch_to_rgb, &lch, &rgb, 1);
/* This is only checking if a color is within the sRGB gamut. I want
* to check compared to the image's space (anySpace) or softproof
* space. TODO.
*/
if (rgb[0] < 0.0 || rgb[0] > 1.0 ||
rgb[1] < 0.0 || rgb[1] > 1.0 ||
rgb[2] < 0.0 || rgb[2] > 1.0)
{
d[0] = scale->oog_color[0];
d[1] = scale->oog_color[1];
d[2] = scale->oog_color[2];
}
else
{
d[0] = rgb[0] * 255;
d[1] = rgb[1] * 255;
d[2] = rgb[2] * 255;
}
}
d = buf + scale->width * 3;
for (y = 1; y < scale->height; y++)
{
memcpy (d, buf, scale->width * 3);
d += scale->width * 3;
}
break;
case GTK_ORIENTATION_VERTICAL:
for (y = 0; y < scale->height; y++)
{
gdouble value = (gdouble) y * multiplier / (gdouble) (scale->height - 1);
guchar u8rgb[3];
if (invert)
value = multiplier - value;
if (channel_value)
*channel_value = value;
else if (channel_value_f)
*channel_value_f = (gfloat) value;
if (from_hsv)
babl_process (fish_hsv_to_rgb, &hsv, &rgb, 1);
else if (from_lch)
babl_process (fish_lch_to_rgb, &lch, &rgb, 1);
if (rgb[0] < 0.0 || rgb[0] > 1.0 ||
rgb[1] < 0.0 || rgb[1] > 1.0 ||
rgb[2] < 0.0 || rgb[2] > 1.0)
{
u8rgb[0] = scale->oog_color[0];
u8rgb[1] = scale->oog_color[1];
u8rgb[2] = scale->oog_color[2];
}
else
{
u8rgb[0] = rgb[0] * 255;
u8rgb[1] = rgb[1] * 255;
u8rgb[2] = rgb[2] * 255;
}
for (x = 0, d = buf; x < scale->width; x++, d += 3)
{
d[0] = u8rgb[0];
d[1] = u8rgb[1];
d[2] = u8rgb[2];
}
buf += scale->width * 3;
}
break;
}
}
static void
gimp_color_scale_render_alpha (GimpColorScale *scale)
{
GtkRange *range = GTK_RANGE (scale);
gdouble rgb[3];
gboolean invert;
gdouble a;
guint x, y;
guchar *buf;
guchar *d, *l;
invert = should_invert (range);
buf = scale->buf;
gegl_color_get_pixel (scale->color,
babl_format_with_space ("R'G'B' double", scale->format),
rgb);
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
{
guchar *light;
guchar *dark;
light = buf;
/* this won't work correctly for very thin scales */
dark = (scale->height > GIMP_CHECK_SIZE_SM ?
buf + GIMP_CHECK_SIZE_SM * 3 * scale->width : light);
for (x = 0, d = light, l = dark; x < scale->width; x++)
{
if ((x % GIMP_CHECK_SIZE_SM) == 0)
{
guchar *t;
t = d;
d = l;
l = t;
}
a = (gdouble) x / (gdouble) (scale->width - 1);
if (invert)
a = 1.0 - a;
l[0] = (GIMP_CHECK_LIGHT + (rgb[0] - GIMP_CHECK_LIGHT) * a) * 255.999;
l[1] = (GIMP_CHECK_LIGHT + (rgb[1] - GIMP_CHECK_LIGHT) * a) * 255.999;
l[2] = (GIMP_CHECK_LIGHT + (rgb[2] - GIMP_CHECK_LIGHT) * a) * 255.999;
l += 3;
d[0] = (GIMP_CHECK_DARK + (rgb[0] - GIMP_CHECK_DARK) * a) * 255.999;
d[1] = (GIMP_CHECK_DARK + (rgb[1] - GIMP_CHECK_DARK) * a) * 255.999;
d[2] = (GIMP_CHECK_DARK + (rgb[2] - GIMP_CHECK_DARK) * a) * 255.999;
d += 3;
}
for (y = 0, d = buf; y < scale->height; y++, d += 3 * scale->width)
{
if (y == 0 || y == GIMP_CHECK_SIZE_SM)
continue;
if ((y / GIMP_CHECK_SIZE_SM) & 1)
memcpy (d, dark, 3 * scale->width);
else
memcpy (d, light, 3 * scale->width);
}
}
break;
case GTK_ORIENTATION_VERTICAL:
{
guchar light[3] = {0xff, 0xff, 0xff};
guchar dark[3] = {0xff, 0xff, 0xff};
for (y = 0, d = buf; y < scale->height; y++, d += scale->width * 3)
{
a = (gdouble) y / (gdouble) (scale->height - 1);
if (invert)
a = 1.0 - a;
light[0] = (GIMP_CHECK_LIGHT + (rgb[0] - GIMP_CHECK_LIGHT) * a) * 255.999;
light[1] = (GIMP_CHECK_LIGHT + (rgb[1] - GIMP_CHECK_LIGHT) * a) * 255.999;
light[2] = (GIMP_CHECK_LIGHT + (rgb[2] - GIMP_CHECK_LIGHT) * a) * 255.999;
dark[0] = (GIMP_CHECK_DARK + (rgb[0] - GIMP_CHECK_DARK) * a) * 255.999;
dark[1] = (GIMP_CHECK_DARK + (rgb[1] - GIMP_CHECK_DARK) * a) * 255.999;
dark[2] = (GIMP_CHECK_DARK + (rgb[2] - GIMP_CHECK_DARK) * a) * 255.999;
for (x = 0, l = d; x < scale->width; x++, l += 3)
{
if (((x / GIMP_CHECK_SIZE_SM) ^ (y / GIMP_CHECK_SIZE_SM)) & 1)
{
l[0] = light[0];
l[1] = light[1];
l[2] = light[2];
}
else
{
l[0] = dark[0];
l[1] = dark[1];
l[2] = dark[2];
}
}
}
}
break;
}
}
static void
gimp_color_scale_notify_config (GimpColorConfig *config,
const GParamSpec *pspec,
GimpColorScale *scale)
{
GeglColor *color;
color = gimp_color_config_get_out_of_gamut_color (config);
/* TODO: shouldn't this be color-managed too, using the target space into
* consideration?
*/
gegl_color_get_pixel (color, babl_format ("R'G'B' u8"), scale->oog_color);
scale->needs_render = TRUE;
g_object_unref (color);
}