1 /*
2 * Some convenience stuff
3 *
4 * Authors:
5 * Lauris Kaplinski <lauris@kaplinski.com>
6 * Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
7 * Jon A. Cruz <jon@joncruz.org>
8 *
9 * Copyright (C) 1999-2002 authors
10 * Copyright (C) 2001-2002 Ximian, Inc.
11 * Copyright (C) 2010 Jasper van de Gronde
12 * Copyright (C) 2010 Jon A. Cruz
13 *
14 * Released under GNU GPL, read the file 'COPYING' for more information
15 */
17 #include <cstdio>
18 #include <cstring>
19 #include <string>
20 #include <ctype.h>
21 #include <map>
22 #include "color.h"
23 #include "sp-cursor.h"
25 void sp_cursor_bitmap_and_mask_from_xpm(GdkBitmap **bitmap, GdkBitmap **mask, gchar const *const *xpm)
26 {
27 int height = 0;
28 int width = 0;
29 int colors = 0;
30 int pix = 0;
31 sscanf(xpm[0], "%d %d %d %d", &height, &width, &colors, &pix);
33 g_return_if_fail(height == 32);
34 g_return_if_fail(width == 32);
35 g_return_if_fail(colors >= 3);
37 int transparent_color = ' ';
38 std::string black_colors;
40 char pixmap_buffer[(32 * 32) / 8] = {0};
41 char mask_buffer[(32 * 32) / 8] = {0};
43 for (int i = 0; i < colors; i++) {
45 char const *p = xpm[1 + i];
46 char const ccode = *p;
48 p++;
49 while (isspace(*p)) {
50 p++;
51 }
52 p++;
53 while (isspace(*p)) {
54 p++;
55 }
57 if (strcmp(p, "None") == 0) {
58 transparent_color = ccode;
59 }
61 if (strcmp(p, "Stroke") == 0) {
62 black_colors.push_back(ccode);
63 }
65 if (strcmp(p, "#000000") == 0) {
66 black_colors.push_back(ccode);
67 }
68 }
70 for (int y = 0; y < 32; y++) {
71 for (int x = 0; x < 32; ) {
72 char value = 0;
73 char maskv = 0;
75 for (int pix = 0; pix < 8; pix++, x++){
76 if (xpm[1 + colors + y][x] != transparent_color) {
77 maskv |= 1 << pix;
79 if (black_colors.find(xpm[1 + colors + y][x]) != std::string::npos) {
80 value |= 1 << pix;
81 }
82 }
83 }
85 pixmap_buffer[(y * 4 + x / 8) - 1] = value;
86 mask_buffer[(y * 4 + x / 8) - 1] = maskv;
87 }
88 }
90 *bitmap = gdk_bitmap_create_from_data(NULL, pixmap_buffer, 32, 32);
91 *mask = gdk_bitmap_create_from_data(NULL, mask_buffer, 32, 32);
92 }
94 static void free_cursor_data(guchar *pixels, gpointer data) {
95 delete [] reinterpret_cast<guint32*>(pixels);
96 }
98 struct RGBA {
99 guchar v[4];
101 RGBA() {
102 v[0] = 0;
103 v[1] = 0;
104 v[2] = 0;
105 v[3] = 0;
106 }
108 RGBA(guchar r, guchar g, guchar b, guchar a) {
109 v[0] = r;
110 v[1] = g;
111 v[2] = b;
112 v[3] = a;
113 }
115 operator guint32() const {
116 guint32 result = (static_cast<guint32>(v[0]) << 0)
117 | (static_cast<guint32>(v[1]) << 8)
118 | (static_cast<guint32>(v[2]) << 16)
119 | (static_cast<guint32>(v[3]) << 24);
120 return result;
121 }
122 };
124 GdkPixbuf *sp_cursor_pixbuf_from_xpm(gchar const *const *xpm, GdkColor const& black, GdkColor const& white, guint32 fill, guint32 stroke)
125 {
126 int height = 0;
127 int width = 0;
128 int colors = 0;
129 int pix = 0;
130 sscanf(xpm[0], "%d %d %d %d", &height, &width, &colors, &pix);
132 //g_return_if_fail (height == 32);
133 //g_return_if_fail (width == 32);
134 //g_return_if_fail (colors >= 3);
136 std::map<char, RGBA> colorMap;
138 for (int i = 0; i < colors; i++) {
140 char const *p = xpm[1 + i];
141 char const ccode = *p;
143 p++;
144 while (isspace(*p)) {
145 p++;
146 }
147 p++;
148 while (isspace(*p)) {
149 p++;
150 }
152 if (strcmp(p, "None") == 0) {
153 colorMap[ccode] = RGBA();
154 } else if (strcmp(p, "Fill") == 0) {
155 colorMap[ccode] = RGBA(SP_RGBA32_R_U(fill), SP_RGBA32_G_U(fill), SP_RGBA32_B_U(fill), SP_RGBA32_A_U(fill));
156 } else if (strcmp(p, "Stroke") == 0) {
157 colorMap[ccode] = RGBA(SP_RGBA32_R_U(stroke), SP_RGBA32_G_U(stroke), SP_RGBA32_B_U(stroke), SP_RGBA32_A_U(stroke));
158 } else if (strcmp(p, "#000000") == 0) {
159 colorMap[ccode] = RGBA(black.red, black.green, black.blue, 255);
160 } else if (strcmp(p, "#FFFFFF") == 0) {
161 colorMap[ccode] = RGBA(white.red, white.green, white.blue, 255);
162 } else {
163 colorMap[ccode] = RGBA();
164 }
165 }
167 guint32 *pixmap_buffer = new guint32[width * height];
169 for (int y = 0; y < height; y++) {
170 for (int x = 0; x < width; x++) {
171 std::map<char, RGBA>::const_iterator it = colorMap.find(xpm[1 + colors + y][x]);
172 pixmap_buffer[y * width + x] = (it == colorMap.end()) ? 0u : it->second;
173 }
174 }
176 return gdk_pixbuf_new_from_data(reinterpret_cast<guchar*>(pixmap_buffer), GDK_COLORSPACE_RGB, TRUE, 8, width, height, width * sizeof(guint32), free_cursor_data, NULL);
177 }
179 GdkCursor *sp_cursor_new_from_xpm(gchar const *const *xpm, gint hot_x, gint hot_y)
180 {
181 GdkCursor *cursor = 0;
182 GdkColor const fg = { 0, 0, 0, 0 };
183 GdkColor const bg = { 0, 65535, 65535, 65535 };
185 GdkBitmap *bitmap = 0;
186 GdkBitmap *mask = 0;
188 sp_cursor_bitmap_and_mask_from_xpm(&bitmap, &mask, xpm);
189 if ( bitmap && mask ) {
190 cursor = gdk_cursor_new_from_pixmap(bitmap, mask,
191 &fg, &bg,
192 hot_x, hot_y);
193 g_object_unref(bitmap);
194 g_object_unref(mask);
195 }
197 return cursor;
198 }
200 /*
201 Local Variables:
202 mode:c++
203 c-file-style:"stroustrup"
204 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
205 indent-tabs-mode:nil
206 fill-column:99
207 End:
208 */
209 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :