/*
*
* LiveWallpaper
*
* 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 3 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, see .
*
* Copyright (C) 2012-2016 Maximilian Schnarr
*
*
* The color mapping functions are taken from livewallpaper-config. They
* were originally inspirated by gnome-terminal (profile-editor.c).
*
* The color conversion functions are inspirated by GIMP:
* http://git.gnome.org/browse/gimp/tree/libgimpcolor/gimpcolorspace.c?id=GIMP_2_6_11
*
*/
/**
* SECTION: color
* @Short_description: various functions for color conversion / handling
* @Title: Color Handling
*
* The following functions provide support for converting colors from one color
* model to another color model. There are also some functions for getting/setting
* #GdkRGBA objects from/to #GSettings strings.
*/
#include
/**
* lw_color_get_color_mapping:
* @value: Return location for the property value
* @variant: The #GVariant
* @p: User data that was specified when the binding was created
*
* This function is used to convert a color from a #GSettings string to a #GdkRGBA
* object. Use this function as get mapping function of g_settings_bind_with_mapping()
* or take a look at the lw_settings_bind_color() macro.
*
* Returns: %TRUE if the conversion succeeded, %FALSE in case of an error
*/
gboolean
lw_color_get_color_mapping(GValue *value, GVariant *variant, gpointer p G_GNUC_UNUSED)
{
const gchar *s;
GdkRGBA rgba;
g_variant_get(variant, "&s", &s);
if(!gdk_rgba_parse(&rgba, s)) return FALSE;
g_value_set_boxed(value, &rgba);
return TRUE;
}
/**
* lw_color_set_color_mapping:
* @value: A #GValue containing the property value to map
* @type: The #GVariantType to create
* @p: User data that was specified when the binding was created
*
* This function is used to convert a #GdkRGBA object to a #GSettings string. Use this
* function as set mapping function of g_settings_bind_with_mapping() or take a look
* at the lw_settings_bind_color() macro.
*
* Returns: A new #GVariant holding the data from value, or %NULL in case of an error
*/
GVariant*
lw_color_set_color_mapping(const GValue *value, const GVariantType *type G_GNUC_UNUSED, gpointer p G_GNUC_UNUSED)
{
return g_variant_new_string( gdk_rgba_to_string(g_value_get_boxed(value)) );
}
/**
* LwHSL:
* @hue: The hue value from 0.0 to 1.0
* @saturation: The saturation value from 0.0 to 1.0
* @lightness: The lightness value from 0.0 to 1.0
*
* This structure represents a color in HSL color space.
*
* Since: 0.4
*/
G_DEFINE_BOXED_TYPE(LwHSL, lw_hsl, lw_hsl_copy, lw_hsl_free)
/**
* lw_hsl_copy:
* @hsl: A #LwHSL
*
* Makes a copy of a #LwHSL structure.
*
* Returns: A newly allocated #LwHSL. It should be freed through lw_hsl_free().
*
* Since: 0.4
*/
LwHSL*
lw_hsl_copy(const LwHSL *hsl)
{
return g_slice_dup(LwHSL, hsl);
}
/**
* lw_hsl_free:
* @hsl: A #LwHSL
*
* Frees a #LwHSL structure created with lw_hsl_copy().
*
* Since: 0.4
*/
void
lw_hsl_free(LwHSL *hsl)
{
g_slice_free(LwHSL, hsl);
}
/**
* lw_rgb_to_hsl:
* @rgb: A #GdkRGBA
*
* Converts a color from the RGB color model to the HSL color model.
* The alpha value of the @rgb param is not used by this function.
*
* Returns: A newly allocated #LwHSL. It should be freed through lw_hsl_free().
*/
LwHSL*
lw_rgb_to_hsl(GdkRGBA *rgb)
{
LwHSL hsl;
gdouble min, max;
gdouble delta;
#define r rgb->red
#define g rgb->green
#define b rgb->blue
#define h hsl.hue
#define s hsl.saturation
#define l hsl.lightness
max = MAX(r, MAX(g, b));
min = MIN(r, MIN(g, b));
l = (max + min) / 2.0;
if(max == min)
{
s = 0.0;
h = 0.0;
}
else
{
delta = max - min;
if(l <= 0.5)
s = delta / (max + min);
else
s = delta / (2.0 - max - min);
if(r == max)
h = (g - b) / delta;
else if(g == max)
h = 2.0 + (b - r) / delta;
else
h = 4.0 + (r - g) / delta;
h /= 6.0;
if(h < 0.0)
h += 1.0;
else if(h > 1.0)
h -= 1.0;
}
#undef r
#undef g
#undef b
#undef h
#undef s
#undef l
return lw_hsl_copy(&hsl);
}
static inline gdouble
hsl_value(gdouble n1, gdouble n2, gdouble hue)
{
if(hue < 0.0)
hue += 6.0;
else if(hue > 6.0)
hue -= 6.0;
if(hue < 1.0)
return n1 + (n2 - n1) * hue;
else if(hue < 3.0)
return n2;
else if(hue < 4.0)
return n1 + (n2 - n1) * (4.0 - hue);
else
return n1;
}
/**
* lw_hsl_to_rgb:
* @hsl: A #LwHSL
*
* Converts a color from the HSL color model to the RGB color model.
* The alpha value of the result will be undefined.
*
* Returns: A newly allocated #GdkRGBA. It should be freed through gdk_rgba_free().
*/
GdkRGBA*
lw_hsl_to_rgb(LwHSL *hsl)
{
GdkRGBA rgb;
#define r rgb.red
#define g rgb.green
#define b rgb.blue
#define h hsl->hue
#define s hsl->saturation
#define l hsl->lightness
if(s == 0.0)
{
r = g = b = l;
}
else
{
gdouble m1, m2;
/* Case 1 */
if(l <= 0.5)
m2 = l * (1.0 + s);
/* Case 2 */
else
m2 = l + s - l * s;
m1 = 2.0 * l - m2;
r = hsl_value(m1, m2, h * 6.0 + 2.0);
g = hsl_value(m1, m2, h * 6.0);
b = hsl_value(m1, m2, h * 6.0 - 2.0);
}
#undef r
#undef g
#undef b
#undef h
#undef s
#undef l
return gdk_rgba_copy(&rgb);
}