1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 #include "gtksymboliccolor.h"
22 #include "gtkstyleproperties.h"
24 #include "gtkwin32themeprivate.h"
27 * SECTION:gtksymboliccolor
28 * @Short_description: Symbolic colors
29 * @Title: GtkSymbolicColor
31 * GtkSymbolicColor is a boxed type that represents a symbolic color.
32 * It is the result of parsing a
33 * <link linkend="gtkcssprovider-symbolic-colors">color expression</link>.
34 * To obtain the color represented by a GtkSymbolicColor, it has to
35 * be resolved with gtk_symbolic_color_resolve(), which replaces all
36 * symbolic color references by the colors they refer to (in a given
37 * context) and evaluates mix, shade and other expressions, resulting
38 * in a #GdkRGBA value.
40 * It is not normally necessary to deal directly with #GtkSymbolicColors,
41 * since they are mostly used behind the scenes by #GtkStyleContext and
45 G_DEFINE_BOXED_TYPE (GtkSymbolicColor, gtk_symbolic_color,
46 gtk_symbolic_color_ref, gtk_symbolic_color_unref)
58 struct _GtkSymbolicColor
70 GtkSymbolicColor *color;
76 GtkSymbolicColor *color1;
77 GtkSymbolicColor *color2;
90 * gtk_symbolic_color_new_literal:
93 * Creates a symbolic color pointing to a literal color.
95 * Returns: a newly created #GtkSymbolicColor
100 gtk_symbolic_color_new_literal (const GdkRGBA *color)
102 GtkSymbolicColor *symbolic_color;
104 g_return_val_if_fail (color != NULL, NULL);
106 symbolic_color = g_slice_new0 (GtkSymbolicColor);
107 symbolic_color->type = COLOR_TYPE_LITERAL;
108 symbolic_color->color = *color;
109 symbolic_color->ref_count = 1;
111 return symbolic_color;
115 * gtk_symbolic_color_new_name:
118 * Creates a symbolic color pointing to an unresolved named
119 * color. See gtk_style_context_lookup_color() and
120 * gtk_style_properties_lookup_color().
122 * Returns: a newly created #GtkSymbolicColor
127 gtk_symbolic_color_new_name (const gchar *name)
129 GtkSymbolicColor *symbolic_color;
131 g_return_val_if_fail (name != NULL, NULL);
133 symbolic_color = g_slice_new0 (GtkSymbolicColor);
134 symbolic_color->type = COLOR_TYPE_NAME;
135 symbolic_color->name = g_strdup (name);
136 symbolic_color->ref_count = 1;
138 return symbolic_color;
142 * gtk_symbolic_color_new_shade: (constructor)
143 * @color: another #GtkSymbolicColor
144 * @factor: shading factor to apply to @color
146 * Creates a symbolic color defined as a shade of
147 * another color. A factor > 1.0 would resolve to
148 * a brighter color, while < 1.0 would resolve to
151 * Returns: A newly created #GtkSymbolicColor
156 gtk_symbolic_color_new_shade (GtkSymbolicColor *color,
159 GtkSymbolicColor *symbolic_color;
161 g_return_val_if_fail (color != NULL, NULL);
163 symbolic_color = g_slice_new0 (GtkSymbolicColor);
164 symbolic_color->type = COLOR_TYPE_SHADE;
165 symbolic_color->shade.color = gtk_symbolic_color_ref (color);
166 symbolic_color->shade.factor = factor;
167 symbolic_color->ref_count = 1;
169 return symbolic_color;
173 * gtk_symbolic_color_new_alpha: (constructor)
174 * @color: another #GtkSymbolicColor
175 * @factor: factor to apply to @color alpha
177 * Creates a symbolic color by modifying the relative alpha
178 * value of @color. A factor < 1.0 would resolve to a more
179 * transparent color, while > 1.0 would resolve to a more
182 * Returns: A newly created #GtkSymbolicColor
187 gtk_symbolic_color_new_alpha (GtkSymbolicColor *color,
190 GtkSymbolicColor *symbolic_color;
192 g_return_val_if_fail (color != NULL, NULL);
194 symbolic_color = g_slice_new0 (GtkSymbolicColor);
195 symbolic_color->type = COLOR_TYPE_ALPHA;
196 symbolic_color->alpha.color = gtk_symbolic_color_ref (color);
197 symbolic_color->alpha.factor = factor;
198 symbolic_color->ref_count = 1;
200 return symbolic_color;
204 * gtk_symbolic_color_new_mix: (constructor)
205 * @color1: color to mix
206 * @color2: another color to mix
207 * @factor: mix factor
209 * Creates a symbolic color defined as a mix of another
210 * two colors. a mix factor of 0 would resolve to @color1,
211 * while a factor of 1 would resolve to @color2.
213 * Returns: A newly created #GtkSymbolicColor
218 gtk_symbolic_color_new_mix (GtkSymbolicColor *color1,
219 GtkSymbolicColor *color2,
222 GtkSymbolicColor *symbolic_color;
224 g_return_val_if_fail (color1 != NULL, NULL);
225 g_return_val_if_fail (color1 != NULL, NULL);
227 symbolic_color = g_slice_new0 (GtkSymbolicColor);
228 symbolic_color->type = COLOR_TYPE_MIX;
229 symbolic_color->mix.color1 = gtk_symbolic_color_ref (color1);
230 symbolic_color->mix.color2 = gtk_symbolic_color_ref (color2);
231 symbolic_color->mix.factor = factor;
232 symbolic_color->ref_count = 1;
234 return symbolic_color;
238 * gtk_symbolic_color_new_win32: (constructor)
239 * @theme_class: The theme class to pull color from
242 * Creates a symbolic color based on the current win32
245 * Note that while this call is availible on all platforms
246 * the actual value returned is not reliable on non-win32
249 * Returns: A newly created #GtkSymbolicColor
254 gtk_symbolic_color_new_win32 (const gchar *theme_class,
257 GtkSymbolicColor *symbolic_color;
259 g_return_val_if_fail (theme_class != NULL, NULL);
261 symbolic_color = g_slice_new0 (GtkSymbolicColor);
262 symbolic_color->type = COLOR_TYPE_WIN32;
263 symbolic_color->win32.theme_class = g_strdup (theme_class);
264 symbolic_color->win32.id = id;
265 symbolic_color->ref_count = 1;
267 return symbolic_color;
271 * gtk_symbolic_color_ref:
272 * @color: a #GtkSymbolicColor
274 * Increases the reference count of @color
276 * Returns: the same @color
281 gtk_symbolic_color_ref (GtkSymbolicColor *color)
283 g_return_val_if_fail (color != NULL, NULL);
291 * gtk_symbolic_color_unref:
292 * @color: a #GtkSymbolicColor
294 * Decreases the reference count of @color, freeing its memory if the
295 * reference count reaches 0.
300 gtk_symbolic_color_unref (GtkSymbolicColor *color)
302 g_return_if_fail (color != NULL);
306 if (color->ref_count == 0)
310 case COLOR_TYPE_NAME:
311 g_free (color->name);
313 case COLOR_TYPE_SHADE:
314 gtk_symbolic_color_unref (color->shade.color);
316 case COLOR_TYPE_ALPHA:
317 gtk_symbolic_color_unref (color->alpha.color);
320 gtk_symbolic_color_unref (color->mix.color1);
321 gtk_symbolic_color_unref (color->mix.color2);
323 case COLOR_TYPE_WIN32:
324 g_free (color->win32.theme_class);
330 g_slice_free (GtkSymbolicColor, color);
335 rgb_to_hls (gdouble *r,
383 s = (max - min) / (max + min);
385 s = (max - min) / (2 - max - min);
389 h = (green - blue) / delta;
390 else if (green == max)
391 h = 2 + (blue - red) / delta;
392 else if (blue == max)
393 h = 4 + (red - green) / delta;
406 hls_to_rgb (gdouble *h,
419 if (lightness <= 0.5)
420 m2 = lightness * (1 + saturation);
422 m2 = lightness + saturation - lightness * saturation;
423 m1 = 2 * lightness - m2;
440 r = m1 + (m2 - m1) * hue / 60;
444 r = m1 + (m2 - m1) * (240 - hue) / 60;
455 g = m1 + (m2 - m1) * hue / 60;
459 g = m1 + (m2 - m1) * (240 - hue) / 60;
470 b = m1 + (m2 - m1) * hue / 60;
474 b = m1 + (m2 - m1) * (240 - hue) / 60;
485 _shade_color (GdkRGBA *color,
491 rgb_to_hls (&temp.red, &temp.green, &temp.blue);
493 temp.green *= factor;
494 if (temp.green > 1.0)
496 else if (temp.green < 0.0)
502 else if (temp.blue < 0.0)
505 hls_to_rgb (&temp.red, &temp.green, &temp.blue);
510 * gtk_symbolic_color_resolve:
511 * @color: a #GtkSymbolicColor
512 * @props: (allow-none): #GtkStyleProperties to use when resolving
513 * named colors, or %NULL
514 * @resolved_color: (out): return location for the resolved color
516 * If @color is resolvable, @resolved_color will be filled in
517 * with the resolved color, and %TRUE will be returned. Generally,
518 * if @color can't be resolved, it is due to it being defined on
519 * top of a named color that doesn't exist in @props.
521 * When @props is %NULL, resolving of named colors will fail, so if
522 * your @color is or references such a color, this function will
525 * Returns: %TRUE if the color has been resolved
530 gtk_symbolic_color_resolve (GtkSymbolicColor *color,
531 GtkStyleProperties *props,
532 GdkRGBA *resolved_color)
534 g_return_val_if_fail (color != NULL, FALSE);
535 g_return_val_if_fail (resolved_color != NULL, FALSE);
536 g_return_val_if_fail (props == NULL || GTK_IS_STYLE_PROPERTIES (props), FALSE);
540 case COLOR_TYPE_LITERAL:
541 *resolved_color = color->color;
543 case COLOR_TYPE_NAME:
545 GtkSymbolicColor *named_color;
550 named_color = gtk_style_properties_lookup_color (props, color->name);
555 return gtk_symbolic_color_resolve (named_color, props, resolved_color);
559 case COLOR_TYPE_SHADE:
563 if (!gtk_symbolic_color_resolve (color->shade.color, props, &shade))
566 _shade_color (&shade, color->shade.factor);
567 *resolved_color = shade;
573 case COLOR_TYPE_ALPHA:
577 if (!gtk_symbolic_color_resolve (color->alpha.color, props, &alpha))
580 *resolved_color = alpha;
581 resolved_color->alpha = CLAMP (alpha.alpha * color->alpha.factor, 0, 1);
587 GdkRGBA color1, color2;
589 if (!gtk_symbolic_color_resolve (color->mix.color1, props, &color1))
592 if (!gtk_symbolic_color_resolve (color->mix.color2, props, &color2))
595 resolved_color->red = CLAMP (color1.red + ((color2.red - color1.red) * color->mix.factor), 0, 1);
596 resolved_color->green = CLAMP (color1.green + ((color2.green - color1.green) * color->mix.factor), 0, 1);
597 resolved_color->blue = CLAMP (color1.blue + ((color2.blue - color1.blue) * color->mix.factor), 0, 1);
598 resolved_color->alpha = CLAMP (color1.alpha + ((color2.alpha - color1.alpha) * color->mix.factor), 0, 1);
604 case COLOR_TYPE_WIN32:
605 return _gtk_win32_theme_color_resolve (color->win32.theme_class,
611 g_assert_not_reached ();
618 * gtk_symbolic_color_to_string:
619 * @color: color to convert to a string
621 * Converts the given @color to a string representation. This is useful
622 * both for debugging and for serialization of strings. The format of
623 * the string may change between different versions of GTK, but it is
624 * guaranteed that the GTK css parser is able to read the string and
625 * create the same symbolic color from it.
627 * Returns: a new string representing @color
630 gtk_symbolic_color_to_string (GtkSymbolicColor *color)
634 g_return_val_if_fail (color != NULL, NULL);
638 case COLOR_TYPE_LITERAL:
639 s = gdk_rgba_to_string (&color->color);
641 case COLOR_TYPE_NAME:
642 s = g_strconcat ("@", color->name, NULL);
644 case COLOR_TYPE_SHADE:
646 char *color_string = gtk_symbolic_color_to_string (color->shade.color);
647 char factor[G_ASCII_DTOSTR_BUF_SIZE];
649 g_ascii_dtostr (factor, sizeof (factor), color->shade.factor);
650 s = g_strdup_printf ("shade (%s, %s)", color_string, factor);
651 g_free (color_string);
654 case COLOR_TYPE_ALPHA:
656 char *color_string = gtk_symbolic_color_to_string (color->shade.color);
657 char factor[G_ASCII_DTOSTR_BUF_SIZE];
659 g_ascii_dtostr (factor, sizeof (factor), color->alpha.factor);
660 s = g_strdup_printf ("alpha (%s, %s)", color_string, factor);
661 g_free (color_string);
666 char *color_string1 = gtk_symbolic_color_to_string (color->mix.color1);
667 char *color_string2 = gtk_symbolic_color_to_string (color->mix.color2);
668 char factor[G_ASCII_DTOSTR_BUF_SIZE];
670 g_ascii_dtostr (factor, sizeof (factor), color->mix.factor);
671 s = g_strdup_printf ("mix (%s, %s, %s)", color_string1, color_string2, factor);
672 g_free (color_string1);
673 g_free (color_string2);
676 case COLOR_TYPE_WIN32:
678 s = g_strdup_printf (GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME"(%s, %d)",
679 color->win32.theme_class, color->win32.id);
683 g_assert_not_reached ();