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., 59 Temple Place, Suite 330, Boston, MA 02111 USA
28 #include "libgeda_priv.h"
30 #ifdef HAVE_LIBDMALLOC
34 COLOR print_colors
[MAX_COLORS
];
36 #define NOCOLOR {0xff, 0xff, 0xff, 0xff, FALSE}
37 #define WHITE {0xff, 0xff, 0xff, 0xff, TRUE}
38 #define GRAY {0x88, 0x88, 0x88, 0xff, TRUE}
39 #define BLACK {0x00, 0x00, 0x00, 0xff, TRUE}
40 #define ENDMAP {0x00, 0x00, 0x00, 0x00, FALSE}
42 static COLOR default_colors
[] = {
43 WHITE
, /* 0: background */
45 BLACK
, /* 2: net-endpoint */
46 BLACK
, /* 3: graphic */
48 BLACK
, /* 5: attribute */
49 BLACK
, /* 6: logic-bubble */
50 BLACK
, /* 7: dots-grid */
51 BLACK
, /* 8: detached-attribute */
54 GRAY
, /* 11: select */
55 GRAY
, /* 12: bounding-box */
56 GRAY
, /* 13: zoom-box */
57 GRAY
, /* 14: stroke */
59 NOCOLOR
, /* 16: output-background */
60 NOCOLOR
, /* 17: freestyle1 */
61 NOCOLOR
, /* 18: freestyle2 */
62 NOCOLOR
, /* 19: freestyle3 */
63 NOCOLOR
, /* 20: freestyle4 */
64 BLACK
, /* 21: junction */
65 GRAY
, /* 22: mesh-grid-major */
66 NOCOLOR
, /* 23: mesh-grid-minor */
70 /*! \brief Initialises the color subsystem
71 * \par Function Description
72 * At the moment, just initialises the print color map.
77 s_color_map_defaults (print_colors
);
80 /*! \brief Initialise a color map to B&W
81 * \par Function Description
82 * Initialises a color map to a simple default: black features on a
83 * white background, with "special" colors as gray.
85 * \warning \a map must be have length of at least #MAX_COLORS.
87 * \param map Color map to initialise.
90 s_color_map_defaults (COLOR
*map
)
93 gboolean reached_end
= FALSE
;
95 for (i
= 0; i
< MAX_COLORS
; i
++) {
97 map
[i
].enabled
= FALSE
;
100 c
= default_colors
[i
];
101 if (c
.a
== 0) { /* Check for end of default map */
110 /* \brief Decode a hexadecimal RGB or RGBA color code.
111 * \par Function Description
112 * Accepts a hexadecimal color code \a rgba of either the form #RRGGBB
113 * or #RRGGBBAA, and parses it to extract the numerical color values,
114 * placing them in the the #guchar pointers passed as arguments. If
115 * the six-digit form is used, the alpha channel is set to full
116 * opacity. If an error occurs during parsing, the return values are
117 * set to solid white.
119 * Note that this function implements similar functionality to
120 * gdk_color_parse(). However, for consistency, <em>only</em> this
121 * function should be used to parse color strings from gEDA
122 * configuration files, as gdk_color_parse() does not support the
125 * \todo Use GError mechanism to give more specific error messages.
127 * \param [in] rgba Colour code to parse.
128 * \param [out] r Location to store red value.
129 * \param [out] g Location to store green value.
130 * \param [out] b Location to store blue value.
132 * \returns #TRUE on success, #FALSE on failure.
135 s_color_rgba_decode (const gchar
*rgba
,
136 guint8
*r
, guint8
*g
, guint8
*b
, guint8
*a
)
138 gint len
, i
, ri
, gi
, bi
, ai
;
141 /* Default to solid white */
142 *r
= 0xff; *g
= 0xff; *b
= 0xff; *a
= 0xff;
144 /* Check that the string is a valid length and starts with a '#' */
146 if ((len
!= 9 && len
!= 7) || rgba
[0] != '#')
149 /* Check we only have [0-9a-fA-F] */
150 for (i
= 1; i
< len
; i
++) {
152 if ((c
< '0' || c
> '9')
153 && (c
< 'a' || c
> 'f')
154 && (c
< 'A' || c
> 'F'))
158 /* Use sscanf to extract values */
159 c
= sscanf (rgba
+ 1, "%2x%2x%2x", &ri
, &gi
, &bi
);
162 *r
= (guint8
) ri
; *g
= (guint8
) gi
; *b
= (guint8
) bi
;
165 c
= sscanf (rgba
+ 7, "%2x", &ai
);
174 /* \brief Encode a hexadecimal RGB or RGBA color code.
175 * \par Function Description
176 * Encodes four colour components into either the form #RRGGBB or
177 * #RRGGBBAA. The shorter form is used when the alpha component is
180 * \param [in] r Red component.
181 * \param [in] g Green component.
182 * \param [in] b Blue component.
183 * \returns A newly allocated string containing the encoded string.
186 s_color_rgba_encode (guint8 r
, guint8 g
, guint8 b
, guint8 a
)
189 return g_strdup_printf("#%02x%02x%02x%02x",
190 (gint
) r
, (gint
) g
, (gint
) b
, (gint
) a
);
192 return g_strdup_printf("#%02x%02x%02x",
193 (gint
) r
, (gint
) g
, (gint
) b
);
196 /*! \todo Finish function documentation!!!
198 * \par Function Description
201 gchar
*s_color_ps_string(gint color
)
205 if (color
>= MAX_COLORS
) {
206 g_warning (_("Color index out of range"));
210 c
= print_colors
[color
];
212 if ((c
.a
== 0) || !c
.enabled
) {
215 return g_strdup_printf ("%.3f %.3f %.3f",
218 (gdouble
) c
.b
/255.0);
223 s_color_map_to_scm (const COLOR
*map
)
225 SCM result
= SCM_EOL
;
227 for (i
= MAX_COLORS
- 1; i
>= 0; i
--) {
228 SCM color_val
= SCM_BOOL_F
;
229 if (map
[i
].enabled
) {
231 gchar
*rgba
= s_color_rgba_encode (c
.r
, c
.g
, c
.b
, c
.a
);
232 color_val
= scm_from_locale_string (rgba
);
235 result
= scm_cons (scm_list_2 (scm_from_int (i
), color_val
), result
);
241 * \warning This function should ONLY be called from Scheme procedures.
244 s_color_map_from_scm (COLOR
*map
, SCM lst
, const char *scheme_proc_name
)
247 SCM wrong_type_arg_sym
= scm_from_locale_symbol ("wrong-type-arg");
248 SCM proc_name
= scm_from_locale_string (scheme_proc_name
);
249 while (curr
!= SCM_EOL
) {
255 SCM entry
= scm_car (curr
);
257 /* Check map entry has correct type */
258 if (!scm_is_true (scm_list_p (entry
))
259 || (scm_to_int (scm_length (entry
)) != 2)) {
260 scm_error_scm (wrong_type_arg_sym
, proc_name
,
261 scm_from_locale_string (_("Color map entry must be a two-element list")),
262 SCM_EOL
, scm_list_1 (entry
));
265 /* Check color index has correct type, and extract it */
267 if (!scm_is_integer (s
)) {
268 scm_error_scm (wrong_type_arg_sym
, proc_name
,
269 scm_from_locale_string (_("Index in color map entry must be an integer")),
270 SCM_EOL
, scm_list_1 (s
));
274 /* Check color index is within bounds. If it's out of bounds, it's
275 * legal, but warn & ignore it.
277 * FIXME one day we will have dynamically-expanding colorspace.
279 if ((i
< 0) || (i
>= MAX_COLORS
)) {
280 g_critical ("Color map index out of bounds: %i\n", i
);
284 /* If color value is #F, disable color */
285 s
= scm_cadr (entry
);
286 if (scm_is_false (s
)) {
287 map
[i
].enabled
= FALSE
;
291 /* Otherwise, we require a string */
292 s
= scm_cadr (entry
);
293 if (!scm_is_string (s
)) {
294 scm_error_scm (wrong_type_arg_sym
, proc_name
,
295 scm_from_locale_string (_("Value in color map entry must be #f or a string")),
296 SCM_EOL
, scm_list_1 (s
));
298 rgba
= scm_to_locale_string (s
);
300 result
= s_color_rgba_decode (rgba
, &c
.r
, &c
.g
, &c
.b
, &c
.a
);
302 /* FIXME should we generate a Guile error if there's a problem here? */
304 g_critical ("Invalid color map value: %s\n", rgba
);
307 map
[i
].enabled
= TRUE
;
311 /* Go to next element in map */
312 curr
= scm_cdr (curr
);
314 scm_remember_upto_here_2 (wrong_type_arg_sym
, proc_name
);