gnetlist: Add basic concatenated net support for verilog.
[geda-gaf/whiteaudio.git] / libgeda / src / s_color.c
blob5dcb07044ef6e92c083d48b97c55314b3b188400
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <config.h>
21 #include <missing.h>
23 #include <stdio.h>
24 #include <math.h>
25 #ifdef HAVE_STRING_H
26 #include <string.h>
27 #endif
29 #include "libgeda_priv.h"
31 #ifdef HAVE_LIBDMALLOC
32 #include <dmalloc.h>
33 #endif
35 COLOR print_colors[MAX_COLORS];
37 #define NOCOLOR {0xff, 0xff, 0xff, 0xff, FALSE}
38 #define WHITE {0xff, 0xff, 0xff, 0xff, TRUE}
39 #define GRAY {0x88, 0x88, 0x88, 0xff, TRUE}
40 #define BLACK {0x00, 0x00, 0x00, 0xff, TRUE}
41 #define ENDMAP {0x00, 0x00, 0x00, 0x00, FALSE}
43 static COLOR default_colors[] = {
44 WHITE, /* 0: background */
45 BLACK, /* 1: pin */
46 BLACK, /* 2: net-endpoint */
47 BLACK, /* 3: graphic */
48 BLACK, /* 4: net */
49 BLACK, /* 5: attribute */
50 BLACK, /* 6: logic-bubble */
51 BLACK, /* 7: dots-grid */
52 BLACK, /* 8: detached-attribute */
53 BLACK, /* 9: text */
54 BLACK, /* 10: bus */
55 GRAY, /* 11: select */
56 GRAY, /* 12: bounding-box */
57 GRAY, /* 13: zoom-box */
58 GRAY, /* 14: stroke */
59 BLACK, /* 15: lock */
60 NOCOLOR, /* 16: output-background */
61 NOCOLOR, /* 17: freestyle1 */
62 NOCOLOR, /* 18: freestyle2 */
63 NOCOLOR, /* 19: freestyle3 */
64 NOCOLOR, /* 20: freestyle4 */
65 BLACK, /* 21: junction */
66 GRAY, /* 22: mesh-grid-major */
67 NOCOLOR, /* 23: mesh-grid-minor */
68 ENDMAP
71 /*! \brief Initialises the color subsystem
72 * \par Function Description
73 * At the moment, just initialises the print color map.
75 void
76 s_color_init(void)
78 s_color_map_defaults (print_colors);
81 /*! \brief Initialise a color map to B&W
82 * \par Function Description
83 * Initialises a color map to a simple default: black features on a
84 * white background, with "special" colors as gray.
86 * \warning \a map must be have length of at least #MAX_COLORS.
88 * \param map Color map to initialise.
90 void
91 s_color_map_defaults (COLOR *map)
93 int i;
94 gboolean reached_end = FALSE;
95 COLOR c;
96 for (i = 0; i < MAX_COLORS; i++) {
97 if (reached_end) {
98 map[i].enabled = FALSE;
99 continue;
101 c = default_colors[i];
102 if (c.a == 0) { /* Check for end of default map */
103 reached_end = TRUE;
104 i--;
105 continue;
107 map[i] = c;
111 /* \brief Decode a hexadecimal RGB or RGBA color code.
112 * \par Function Description
113 * Accepts a hexadecimal color code \a rgba of either the form #RRGGBB
114 * or #RRGGBBAA, and parses it to extract the numerical color values,
115 * placing them in the the #guchar pointers passed as arguments. If
116 * the six-digit form is used, the alpha channel is set to full
117 * opacity. If an error occurs during parsing, the return values are
118 * set to solid white.
120 * Note that this function implements similar functionality to
121 * gdk_color_parse(). However, for consistency, <em>only</em> this
122 * function should be used to parse color strings from gEDA
123 * configuration files, as gdk_color_parse() does not support the
124 * alpha channel.
126 * \todo Use GError mechanism to give more specific error messages.
128 * \param [in] rgba Colour code to parse.
129 * \param [out] r Location to store red value.
130 * \param [out] g Location to store green value.
131 * \param [out] b Location to store blue value.
133 * \returns #TRUE on success, #FALSE on failure.
135 gboolean
136 s_color_rgba_decode (const gchar *rgba,
137 guint8 *r, guint8 *g, guint8 *b, guint8 *a)
139 gint len, i, ri, gi, bi, ai;
140 gchar c;
142 /* Default to solid white */
143 *r = 0xff; *g = 0xff; *b = 0xff; *a = 0xff;
145 /* Check that the string is a valid length and starts with a '#' */
146 len = strlen (rgba);
147 if ((len != 9 && len != 7) || rgba[0] != '#')
148 return FALSE;
150 /* Check we only have [0-9a-fA-F] */
151 for (i = 1; i < len; i++) {
152 c = rgba[i];
153 if ((c < '0' || c > '9')
154 && (c < 'a' || c > 'f')
155 && (c < 'A' || c > 'F'))
156 return FALSE;
159 /* Use sscanf to extract values */
160 c = sscanf (rgba + 1, "%2x%2x%2x", &ri, &gi, &bi);
161 if (c != 3)
162 return FALSE;
163 *r = (guint8) ri; *g = (guint8) gi; *b = (guint8) bi;
165 if (len == 9) {
166 c = sscanf (rgba + 7, "%2x", &ai);
167 if (c != 1)
168 return FALSE;
169 *a = (guint8) ai;
172 return TRUE;
175 /* \brief Encode a hexadecimal RGB or RGBA color code.
176 * \par Function Description
177 * Encodes four colour components into either the form #RRGGBB or
178 * #RRGGBBAA. The shorter form is used when the alpha component is
179 * 0xff.
181 * \param [in] r Red component.
182 * \param [in] g Green component.
183 * \param [in] b Blue component.
184 * \returns A newly allocated string containing the encoded string.
186 gchar *
187 s_color_rgba_encode (guint8 r, guint8 g, guint8 b, guint8 a)
189 if (a < 0xff)
190 return g_strdup_printf("#%02x%02x%02x%02x",
191 (gint) r, (gint) g, (gint) b, (gint) a);
192 else
193 return g_strdup_printf("#%02x%02x%02x",
194 (gint) r, (gint) g, (gint) b);
197 /*! \todo Finish function documentation!!!
198 * \brief
199 * \par Function Description
202 gchar *s_color_ps_string(gint color)
204 COLOR c;
206 if (color >= MAX_COLORS) {
207 g_warning (_("Color index out of range"));
208 return NULL;
211 c = print_colors[color];
213 if ((c.a == 0) || !c.enabled) {
214 return NULL;
215 } else {
216 return g_strdup_printf ("%.3f %.3f %.3f",
217 (gdouble) c.r/255.0,
218 (gdouble) c.g/255.0,
219 (gdouble) c.b/255.0);
224 s_color_map_to_scm (const COLOR *map)
226 SCM result = SCM_EOL;
227 int i;
228 for (i = MAX_COLORS - 1; i >= 0; i--) {
229 SCM color_val = SCM_BOOL_F;
230 if (map[i].enabled) {
231 COLOR c = map[i];
232 gchar *rgba = s_color_rgba_encode (c.r, c.g, c.b, c.a);
233 color_val = scm_from_utf8_string (rgba);
234 g_free (rgba);
236 result = scm_cons (scm_list_2 (scm_from_int (i), color_val), result);
238 return result;
242 * \warning This function should ONLY be called from Scheme procedures.
244 void
245 s_color_map_from_scm (COLOR *map, SCM lst, const char *scheme_proc_name)
247 SCM curr = lst;
248 SCM wrong_type_arg_sym = scm_from_utf8_symbol ("wrong-type-arg");
249 SCM proc_name = scm_from_utf8_string (scheme_proc_name);
250 while (curr != SCM_EOL) {
251 int i;
252 char *rgba;
253 SCM s;
254 COLOR c;
255 gboolean result;
256 SCM entry = scm_car (curr);
258 /* Check map entry has correct type */
259 if (!scm_is_true (scm_list_p (entry))
260 || (scm_to_int (scm_length (entry)) != 2)) {
261 scm_error_scm (wrong_type_arg_sym, proc_name,
262 scm_from_utf8_string (_("Color map entry must be a two-element list")),
263 SCM_EOL, scm_list_1 (entry));
266 /* Check color index has correct type, and extract it */
267 s = scm_car (entry);
268 if (!scm_is_integer (s)) {
269 scm_error_scm (wrong_type_arg_sym, proc_name,
270 scm_from_utf8_string (_("Index in color map entry must be an integer")),
271 SCM_EOL, scm_list_1 (s));
273 i = scm_to_int (s);
275 /* Check color index is within bounds. If it's out of bounds, it's
276 * legal, but warn & ignore it.
278 * FIXME one day we will have dynamically-expanding colorspace.
279 * One day. */
280 if ((i < 0) || (i >= MAX_COLORS)) {
281 g_critical ("Color map index out of bounds: %i\n", i);
282 goto color_map_next;
285 /* If color value is #F, disable color */
286 s = scm_cadr (entry);
287 if (scm_is_false (s)) {
288 map[i].enabled = FALSE;
289 goto color_map_next;
292 /* Otherwise, we require a string */
293 s = scm_cadr (entry);
294 if (!scm_is_string (s)) {
295 scm_error_scm (wrong_type_arg_sym, proc_name,
296 scm_from_utf8_string (_("Value in color map entry must be #f or a string")),
297 SCM_EOL, scm_list_1 (s));
299 rgba = scm_to_utf8_string (s);
301 result = s_color_rgba_decode (rgba, &c.r, &c.g, &c.b, &c.a);
303 /* FIXME should we generate a Guile error if there's a problem here? */
304 if (!result) {
305 g_critical ("Invalid color map value: %s\n", rgba);
306 } else {
307 map[i] = c;
308 map[i].enabled = TRUE;
311 color_map_next:
312 /* Go to next element in map */
313 curr = scm_cdr (curr);
315 scm_remember_upto_here_2 (wrong_type_arg_sym, proc_name);