Code

5ec80c9f644a19fb93c38e05345038f7bfd253bd
[inkscape.git] / src / sp-cursor.cpp
1 #define __SP_CURSOR_C__
3 /*
4  * Some convenience stuff
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *
9  * Copyright (C) 1999-2002 authors
10  * Copyright (C) 2001-2002 Ximian, Inc.
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #include <cstdio>
16 #include <cstring>
17 #include <string>
18 #include <ctype.h>
19 #include <map>
20 #include "color.h"
21 #include "sp-cursor.h"
23 void
24 sp_cursor_bitmap_and_mask_from_xpm(GdkBitmap **bitmap, GdkBitmap **mask, gchar const *const *xpm)
25 {
26     int height;
27     int width;
28     int colors;
29     int pix;
30     sscanf(xpm[0], "%d %d %d %d", &height, &width, &colors, &pix);
32     g_return_if_fail (height == 32);
33     g_return_if_fail (width == 32);
34     g_return_if_fail (colors >= 3);
36     int transparent_color = ' ';
37     std::string black_colors;
39     char pixmap_buffer[(32 * 32)/8];
40     char mask_buffer[(32 * 32)/8];
42     for (int i = 0; i < colors; i++) {
44         char const *p = xpm[1 + i];
45         char const ccode = *p;
47         p++;
48         while (isspace(*p)) {
49             p++;
50         }
51         p++;
52         while (isspace(*p)) {
53             p++;
54         }
56         if (strcmp(p, "None") == 0) {
57             transparent_color = ccode;
58         }
60         if (strcmp(p, "Stroke") == 0) {
61             black_colors.push_back(ccode);
62         }
64         if (strcmp(p, "#000000") == 0) {
65             black_colors.push_back(ccode);
66         }
67     }
69     for (int y = 0; y < 32; y++) {
70         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];
100     RGBA() { v[0] = 0; v[1] = 0; v[2] = 0; v[3] = 0; }
101     RGBA(guchar r, guchar g, guchar b, guchar a) { v[0] = r; v[1] = g; v[2] = b; v[3] = a; }
102     operator guint32 const () const { return *reinterpret_cast<guint32 const *>(v); }
103 };
105 GdkPixbuf*
106 sp_cursor_pixbuf_from_xpm(gchar const *const *xpm, GdkColor const& black, GdkColor const& white, guint32 fill, guint32 stroke)
108     int height;
109     int width;
110     int colors;
111     int pix;
112     sscanf(xpm[0], "%d %d %d %d", &height, &width, &colors, &pix);
114     //g_return_if_fail (height == 32);
115     //g_return_if_fail (width == 32);
116     //g_return_if_fail (colors >= 3);
118     std::map<char,RGBA> colorMap;
120     for (int i = 0; i < colors; i++) {
122         char const *p = xpm[1 + i];
123         char const ccode = *p;
125         p++;
126         while (isspace(*p)) {
127             p++;
128         }
129         p++;
130         while (isspace(*p)) {
131             p++;
132         }
134         if (strcmp(p, "None") == 0) {
135             colorMap.insert(std::make_pair(ccode, RGBA()));
136         } else if (strcmp(p, "Fill") == 0) {
137             colorMap.insert(std::make_pair(ccode, RGBA(SP_RGBA32_R_U(fill),SP_RGBA32_G_U(fill),SP_RGBA32_B_U(fill),SP_RGBA32_A_U(fill))));
138         } else if (strcmp(p, "Stroke") == 0) {
139             colorMap.insert(std::make_pair(ccode, RGBA(SP_RGBA32_R_U(stroke),SP_RGBA32_G_U(stroke),SP_RGBA32_B_U(stroke),SP_RGBA32_A_U(stroke))));
140         } else if (strcmp(p, "#000000") == 0) {
141             colorMap.insert(std::make_pair(ccode, RGBA(black.red,black.green,black.blue,255)));
142         } else if (strcmp(p, "#FFFFFF") == 0) {
143             colorMap.insert(std::make_pair(ccode, RGBA(white.red,white.green,white.blue,255)));
144         } else {
145             colorMap.insert(std::make_pair(ccode, RGBA()));
146         }
147     }
149     guint32 *pixmap_buffer = new guint32[width * height];
151     for (int y = 0; y < height; y++) {
152         for (int x = 0; x < width; x++) {
153             std::map<char,RGBA>::const_iterator it = colorMap.find(xpm[1+colors+y][x]);
154             pixmap_buffer[y * width + x] = it==colorMap.end() ? 0u : it->second;
155         }
156     }
158     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);
161 GdkCursor *
162 sp_cursor_new_from_xpm(gchar const *const *xpm, gint hot_x, gint hot_y)
164     GdkColor const fg = { 0, 0, 0, 0 };
165     GdkColor const bg = { 0, 65535, 65535, 65535 };
167     GdkBitmap *bitmap = NULL;
168     GdkBitmap *mask = NULL;
170     sp_cursor_bitmap_and_mask_from_xpm (&bitmap, &mask, xpm);
171     if ( bitmap != NULL && mask != NULL ) {
172         GdkCursor *new_cursor = gdk_cursor_new_from_pixmap (bitmap, mask,
173                                            &fg, &bg,
174                                            hot_x, hot_y);
175         g_object_unref (bitmap);
176         g_object_unref (mask);
177         return new_cursor;
178     }
180     return NULL;
183 /*
184   Local Variables:
185   mode:c++
186   c-file-style:"stroustrup"
187   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
188   indent-tabs-mode:nil
189   fill-column:99
190   End:
191 */
192 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :