]> Pileus Git - ~andy/gtk/blob - gdk/gdkrgba.c
Add tests for GdkRGBA serialization
[~andy/gtk] / gdk / gdkrgba.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #include "config.h"
28 #include "gdkrgba.h"
29 #include <string.h>
30
31 /**
32  * SECTION:rgba_colors
33  * @Short_description: RGBA colors
34  * @Title: RGBA Colors
35  */
36
37 G_DEFINE_BOXED_TYPE (GdkRGBA, gdk_rgba,
38                      gdk_rgba_copy, gdk_rgba_free)
39
40 /**
41  * gdk_rgba_copy:
42  * @rgba: a #GdkRGBA
43  *
44  * Makes a copy of a #GdkRGBA structure, the result must be freed
45  * through gdk_rgba_free().
46  *
47  * Returns: A newly allocated #GdkRGBA
48  **/
49 GdkRGBA *
50 gdk_rgba_copy (GdkRGBA *rgba)
51 {
52   GdkRGBA *copy;
53
54   copy = g_slice_new (GdkRGBA);
55   copy->red = rgba->red;
56   copy->green = rgba->green;
57   copy->blue = rgba->blue;
58   copy->alpha = rgba->alpha;
59
60   return copy;
61 }
62
63 /**
64  * gdk_rgba_free:
65  * @rgba: a #GdkRGBA
66  *
67  * Frees a #GdkRGBA struct created with gdk_rgba_copy()
68  **/
69 void
70 gdk_rgba_free (GdkRGBA *rgba)
71 {
72   g_slice_free (GdkRGBA, rgba);
73 }
74
75 /**
76  * gdk_rgba_parse:
77  * @spec: the string specifying the color
78  * @rgba: the #GdkRGBA struct to fill in
79  *
80  * Parses a textual representation of a color, filling in
81  * the <structfield>red</structfield>, <structfield>green</structfield>,
82  * <structfield>blue</structfield> and <structfield>alpha</structfield>
83  * fields of the @rgba struct.
84  *
85  * The string can be either one of:
86  * <itemizedlist>
87  * <listitem>
88  * A standard name (Taken from the X11 rgb.txt file).
89  * </listitem>
90  * <listitem>
91  * A hex value in the form '#rgb' '#rrggbb' '#rrrgggbbb' or '#rrrrggggbbbb'
92  * </listitem>
93  * <listitem>
94  * A RGB color in the form 'rgb(r,g,b)' (In this case the color will
95  * have full opacity)
96  * </listitem>
97  * <listitem>
98  * A RGBA color in the form 'rgba(r,g,b,a)'
99  * </listitem>
100  * </itemizedlist>
101  *
102  * Where 'r', 'g', 'b' and 'a' are respectively the red, green, blue and
103  * alpha color values, parsed in the last 2 cases as double numbers in
104  * the range [0..1], any other value out of that range will be clamped.
105  *
106  * Returns: %TRUE if the parsing succeeded
107  **/
108 gboolean
109 gdk_rgba_parse (const gchar *spec,
110                 GdkRGBA     *rgba)
111 {
112   gboolean has_alpha;
113   gdouble r, g, b, a;
114   gchar *str = (gchar *) spec;
115
116 #define SKIP_WHITESPACES(s) while (*(s) == ' ') (s)++;
117
118   if (strncmp (str, "rgba", 4) == 0)
119     {
120       has_alpha = TRUE;
121       str += 4;
122     }
123   else if (strncmp (str, "rgb", 3) == 0)
124     {
125       has_alpha = FALSE;
126       a = 1;
127       str += 3;
128     }
129   else
130     {
131       PangoColor pango_color;
132
133       /* Resort on PangoColor for rgb.txt color
134        * map and '#' prefixed colors */
135       if (pango_color_parse (&pango_color, str))
136         {
137           if (rgba)
138             {
139               rgba->red = pango_color.red / 65535.;
140               rgba->green = pango_color.green / 65535.;
141               rgba->blue = pango_color.blue / 65535.;
142               rgba->alpha = 1;
143             }
144
145           return TRUE;
146         }
147       else
148         return FALSE;
149     }
150
151   SKIP_WHITESPACES (str);
152
153   if (*str != '(')
154     return FALSE;
155
156   str++;
157
158   /* Parse red */
159   SKIP_WHITESPACES (str);
160   r = g_ascii_strtod (str, &str);
161   SKIP_WHITESPACES (str);
162
163   if (*str != ',')
164     return FALSE;
165
166   str++;
167
168   /* Parse green */
169   SKIP_WHITESPACES (str);
170   g = g_ascii_strtod (str, &str);
171   SKIP_WHITESPACES (str);
172
173   if (*str != ',')
174     return FALSE;
175
176   str++;
177
178   /* Parse blue */
179   SKIP_WHITESPACES (str);
180   b = g_ascii_strtod (str, &str);
181   SKIP_WHITESPACES (str);
182
183   if (has_alpha)
184     {
185       if (*str != ',')
186         return FALSE;
187
188       str++;
189
190       SKIP_WHITESPACES (str);
191       a = g_ascii_strtod (str, &str);
192       SKIP_WHITESPACES (str);
193     }
194
195   if (*str != ')')
196     return FALSE;
197
198 #undef SKIP_WHITESPACES
199
200   if (rgba)
201     {
202       rgba->red = CLAMP (r, 0, 1);
203       rgba->green = CLAMP (g, 0, 1);
204       rgba->blue = CLAMP (b, 0, 1);
205       rgba->alpha = CLAMP (a, 0, 1);
206     }
207
208   return TRUE;
209 }
210
211 /**
212  * gdk_rgba_hash:
213  * @p: a #GdkRGBA pointer.
214  *
215  * A hash function suitable for using for a hash
216  * table that stores #GdkRGBA<!-- -->s.
217  *
218  * Return value: The hash function applied to @p
219  **/
220 guint
221 gdk_rgba_hash (gconstpointer p)
222 {
223   const GdkRGBA *rgba = p;
224
225   return ((guint) (rgba->red * 65535) +
226           ((guint) (rgba->green * 65535) << 11) +
227           ((guint) (rgba->blue * 65535) << 22) +
228           ((guint) (rgba->alpha * 65535) >> 6));
229 }
230
231 /**
232  * gdk_rgba_equal:
233  * @p1: a #GdkRGBA pointer.
234  * @p2: another #GdkRGBA pointer.
235  *
236  * Compares two RGBA colors.
237  *
238  * Return value: %TRUE if the two colors compare equal
239  **/
240 gboolean
241 gdk_rgba_equal (gconstpointer p1,
242                 gconstpointer p2)
243 {
244   const GdkRGBA *rgba1, *rgba2;
245
246   rgba1 = p1;
247   rgba2 = p2;
248
249   if (rgba1->red == rgba2->red &&
250       rgba1->green == rgba2->green &&
251       rgba1->blue == rgba2->blue &&
252       rgba1->alpha == rgba2->alpha)
253     return TRUE;
254
255   return FALSE;
256 }
257
258 /**
259  * gdk_rgba_to_string:
260  * @rgba: a #GdkRGBA
261  *
262  * Returns a textual specification of @rgba in the form
263  * <literal>rgba (r, g, b, a)</literal>, where 'r', 'g',
264  * 'b' and 'a' represent the red, green, blue and alpha
265  * values respectively.
266  *
267  * Returns: A newly allocated text string
268  **/
269 gchar *
270 gdk_rgba_to_string (GdkRGBA *rgba)
271 {
272   gchar red[G_ASCII_DTOSTR_BUF_SIZE];
273   gchar green[G_ASCII_DTOSTR_BUF_SIZE];
274   gchar blue[G_ASCII_DTOSTR_BUF_SIZE];
275   gchar alpha[G_ASCII_DTOSTR_BUF_SIZE];
276
277   g_ascii_dtostr (red, G_ASCII_DTOSTR_BUF_SIZE, CLAMP (rgba->red, 0, 1));
278   g_ascii_dtostr (green, G_ASCII_DTOSTR_BUF_SIZE, CLAMP (rgba->green, 0, 1));
279   g_ascii_dtostr (blue, G_ASCII_DTOSTR_BUF_SIZE, CLAMP (rgba->blue, 0, 1));
280   g_ascii_dtostr (alpha, G_ASCII_DTOSTR_BUF_SIZE, CLAMP (rgba->alpha, 0, 1));
281
282   return g_strdup_printf ("rgba(%s,%s,%s,%s)", red, green, blue, alpha);
283 }