Code

Fix change in revision 9947 to be consistent with rest of the codebase.
[inkscape.git] / src / sp-cursor.cpp
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;
74                         
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)
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);
179 GdkCursor *sp_cursor_new_from_xpm(gchar const *const *xpm, gint hot_x, gint hot_y)
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;
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 :