1 /*
2  * GraphApp - Cross-Platform Graphics Programming Library.
3  *
4  * File: cursors.c -- change the mouse cursor's shape.
5  * Platform: Windows  Version: 2.35  Date: 1998/04/04
6  *
7  * Version: 1.00  Changes: Original version by Lachlan Patrick.
8  * Version: 1.05  Changes: Moved setcursor() into context.c
9  * Version: 2.00  Changes: New object class mechanism.
10  * Version: 2.30  Changes: Now uses cursor_base.
11  * Version: 2.35  Changes: New reference count technique.
12  */
13 
14 /* Copyright (C) 1993-1998 Lachlan Patrick
15 
16    This file is part of GraphApp, a cross-platform C graphics library.
17 
18    GraphApp is free software; you can redistribute it and/or modify it
19    under the terms of the GNU Library General Public License.
20    GraphApp is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY.
22 
23    See the file COPYLIB.TXT for details.
24 */
25 
26 /* Changes for Windows:
27 
28    add cross cursor
29 
30  */
31 
32 #include "internal.h"
33 
34 __declspec(dllexport) cursor	ArrowCursor = NULL;
35 __declspec(dllexport) cursor	BlankCursor = NULL;
36 __declspec(dllexport) cursor	WatchCursor = NULL;
37 __declspec(dllexport) cursor	CaretCursor = NULL;
38 __declspec(dllexport) cursor	TextCursor  = NULL;
39 __declspec(dllexport) cursor	HandCursor  = NULL;
40 __declspec(dllexport) cursor	CrossCursor  = NULL;
41 
42 /*
43  *  Define the 'Hand' image shape:
44  */
45 
46 static rgb cursor_cmap [] = {
47     0x00000000L,
48     0x00FFFFFFL,
49     0xFFFFFFFFL,
50 };
51 
52 static GAbyte hand_pixels [] = {
53     2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,
54     2,2,2,2,2,0,1,1,0,0,2,2,2,2,2,2,
55     2,2,2,2,2,0,1,1,0,0,2,2,2,2,2,2,
56     2,2,2,2,2,0,1,1,0,0,2,2,2,2,2,2,
57     2,2,2,2,2,0,1,1,0,0,2,2,2,2,2,2,
58     2,2,2,2,2,0,1,1,0,0,2,2,2,2,2,2,
59     2,0,0,0,2,0,1,1,0,0,0,0,0,2,2,2,
60     0,1,1,0,0,0,1,1,0,1,0,1,0,0,0,2,
61     2,0,1,1,0,0,1,1,0,1,0,1,0,1,0,0,
62     2,2,0,1,1,0,1,1,1,1,1,1,0,1,0,0,
63     2,2,0,1,1,0,1,1,1,1,1,1,1,1,0,0,
64     2,2,2,0,1,1,1,1,1,1,1,1,1,1,0,0,
65     2,2,2,2,0,1,1,1,1,1,1,1,1,1,0,0,
66     2,2,2,2,0,1,1,1,1,1,1,1,1,0,0,2,
67     2,2,2,2,2,0,1,1,1,1,1,1,1,0,0,2,
68     2,2,2,2,2,0,1,1,1,1,1,1,1,0,0,2,
69 };
70 
71 static imagedata hand_imagedata = {
72     8,	/* depth */
73     16,	/* width */
74     16,	/* height */
75     3,	/* cmapsize */
76     cursor_cmap,
77     hand_pixels
78 };
79 
80 static image hand_image = & hand_imagedata;
81 static point hand_hotspot = {7,0};
82 
83 /*
84  *  Private cursor destructor.
85  */
private_delcursor(cursor c)86 static void private_delcursor(cursor c)
87 {
88     DestroyCursor(c->handle);
89 }
90 
91 /*
92  *  Private constructor.
93  */
get_cursor_base(void)94 static object get_cursor_base(void)
95 {
96     static object cursor_base = NULL;
97 
98     if (! cursor_base)
99 	cursor_base = new_object(BaseObject, 0, NULL);
100     return cursor_base;
101 }
102 
new_cursor_object(HCURSOR hc)103 static cursor new_cursor_object(HCURSOR hc)
104 {
105     cursor c = new_object(CursorObject, hc, get_cursor_base());
106     if (c) {
107 	c->rect = rect(0,0,16,16);
108 	c->depth = 1;
109 	c->die = private_delcursor;
110     }
111     return c;
112 }
113 
114 /*
115  *  Public constructors.
116  */
createcursor(point offset,GAbyte * white,GAbyte * black)117 cursor createcursor(point offset, GAbyte *white, GAbyte *black)
118 {
119     cursor c;
120     HCURSOR hc;
121     GAbyte *andmask;	/* andmask = ~blackmask & ~whitemask */
122     GAbyte *xormask;	/* xormask = ~blackmask &  whitemask */
123     int w, y;
124     int max_width, max_height, row_bytes;
125 
126     /* Library cursors: D = (D | whitemask) & ~blackmask */
127     /* MS-Windows does: D = (D & andmask) ^ xormask */
128 
129     /* Determine the best cursor size: */
130     max_width  = GetSystemMetrics(SM_CXCURSOR);
131     max_height = GetSystemMetrics(SM_CYCURSOR);
132     row_bytes  = (max_width + 7) / 8;
133 
134     /* Create the data arrays: */
135     andmask = array(max_height * row_bytes, GAbyte);
136     xormask = array(max_height * row_bytes, GAbyte);
137 
138     /* Assign the data into the arrays: */
139     for (y=0; y < max_height; y++) {
140 	for (w=0; w < row_bytes; w++) {
141 	    if ((w<2) && (y<16)) {
142 		andmask[w+y*row_bytes] = ~(black[w+y*2]) & ~(white[w+y*2]);
143 		xormask[w+y*row_bytes] = ~(black[w+y*2]) &  (white[w+y*2]);
144 	    }
145 	    else {
146 		andmask[w+y*row_bytes] = 0xFF;
147 		xormask[w+y*row_bytes] = 0x00;
148 	    }
149 	}
150     }
151 
152     /* Create the cursor: */
153     hc = CreateCursor (this_instance, -offset.x, -offset.y,
154 		       max_width, max_height,
155 		       (void FAR *) andmask, (void FAR *) xormask);
156 
157     c = new_cursor_object(hc);
158 
159     /* Clean up: */
160     discard(andmask);
161     discard(xormask);
162 
163     return c;
164 }
165 
form_and_byte(image img,int x,int y)166 static GAbyte form_and_byte(image img, int x, int y)
167 {
168     int i;
169     rgb pixel;
170     GAbyte result = 0x00;
171 
172     for (i=0; i<8; i++) {
173 	result <<= 1;
174 	pixel = get_monochrome_pixel(img, x+i, y);
175 	if (pixel == Transparent)
176 	    result |= 0x01;
177     }
178     return result;
179 }
180 
form_xor_byte(image img,int x,int y)181 static GAbyte form_xor_byte(image img, int x, int y)
182 {
183     int i;
184     rgb pixel;
185     GAbyte result = 0x00;
186 
187     for (i=0; i<8; i++) {
188 	result <<= 1;
189 	pixel = get_monochrome_pixel(img, x+i, y);
190 	if (pixel == White)
191 	    result |= 0x01;
192     }
193     return result;
194 }
195 
newcursor(point p,image img)196 cursor newcursor(point p, image img)
197 {
198     cursor c;
199     HCURSOR hc;
200     GAbyte *andmask;
201     GAbyte *xormask;
202     int w, y;
203     int max_width, max_height, row_bytes;
204 
205     if (! img) return NULL;
206 
207     /* Determine the best cursor size: */
208     max_width  = GetSystemMetrics(SM_CXCURSOR);
209     max_height = GetSystemMetrics(SM_CYCURSOR);
210     row_bytes  = (max_width + 7) / 8;
211 
212     /* Create the data arrays: */
213     andmask = array(max_height * row_bytes, GAbyte);
214     xormask = array(max_height * row_bytes, GAbyte);
215 
216     /* Assign the data into the arrays: */
217     for (y=0; y < max_height; y++) {
218 	for (w=0; w < row_bytes; w++) {
219 	    andmask[w+y*row_bytes] = form_and_byte(img, w*8, y);
220 	    xormask[w+y*row_bytes] = form_xor_byte(img, w*8, y);
221 	}
222     }
223 
224     /* Create the cursor: */
225     hc = CreateCursor (this_instance, p.x, p.y,
226 		       max_width, max_height,
227 		       (void FAR *) andmask, (void FAR *) xormask);
228 
229     c = new_cursor_object(hc);
230 
231     /* Clean up: */
232     discard(andmask);
233     discard(xormask);
234 
235     return c;
236 }
237 
238 #ifdef UNUSED
239 /*
240  *  Load a cursor from resources.
241  */
load_hotspot(const char * filename)242 static point load_hotspot(const char *filename)
243 {
244     FILE *file;
245     char line[100];
246     int i, x, y;
247     point p = pt(0,0);
248 
249     file = fopen(filename, "rt");
250     while (fgets(line, sizeof(line)-2, file)) {
251 	if ( (! strncmp(line, "point", 5))
252 	     || (! strncmp(line, "/* point", 8)) )
253 	{
254 	    i = 5;
255 	    x = y = 0;
256 	    while (line[i] && (! isdigit(line[i])) )
257 		i++; /* skip "hotspot = {" */
258 	    x = atoi(line+i);
259 	    while (line[i] && isdigit(line[i]))
260 		i++; /* skip x-location */
261 	    while (line[i] && (! isdigit(line[i])) )
262 		i++; /* skip comma */
263 	    y = atoi(line+i);
264 	    p = pt(x,y);
265 	    break;
266 	}
267     }
268     fclose(file);
269     return p;
270 }
271 
load_image_cursor(const char * filename)272 static cursor load_image_cursor(const char *filename)
273 {
274     cursor c = NULL;
275     image img;
276     point p;
277 
278     img = loadimage(filename);
279     if (img) {
280 	p = load_hotspot(filename);
281 	c = newcursor(p, img);
282 	delimage(img);
283     }
284     return c;
285 }
286 
loadcursor(const char * name)287 cursor loadcursor(const char *name)
288 {
289     HCURSOR hc;
290     cursor c;
291 
292     if (this_instance == 0)
293 	return ArrowCursor;
294 
295     hc = LoadCursor(this_instance, name);
296 
297     if (hc)	c = new_cursor_object(hc);
298     else	c = load_image_cursor(name);
299 
300     if (c)	c->text = new_string(name);
301 
302     return c;
303 }
304 #endif
305 
306 /*
307  *  Private cursor initialisation routines.
308  */
make_special_cursor(const char * name,LPCSTR idc)309 static cursor make_special_cursor(const char *name, LPCSTR idc)
310 {
311     cursor c;
312 
313     if (idc) c = new_cursor_object(LoadCursor(0, idc));
314     else	 c = new_cursor_object(NULL);
315 
316     if (c) {
317 	c->text = new_string(name);
318 	protect_object(c);
319     }
320     return c;
321 }
322 
323 PROTECTED
init_cursors(void)324 void init_cursors(void)
325 {
326     ArrowCursor = make_special_cursor("ArrowCursor", IDC_ARROW);
327     BlankCursor = make_special_cursor("BlankCursor", NULL);
328     WatchCursor = make_special_cursor("WatchCursor", IDC_WAIT);
329     CaretCursor = make_special_cursor("CaretCursor", IDC_IBEAM);
330     TextCursor  = make_special_cursor("TextCursor",  IDC_IBEAM);
331     CrossCursor = make_special_cursor("CrossCursor",  IDC_CROSS);
332 
333     HandCursor  = newcursor(hand_hotspot, hand_image);
334     if (HandCursor) {
335 	settext(HandCursor, "HandCursor");
336 	protect_object(HandCursor);
337     }
338 
339     setcursor(ArrowCursor);
340 }
341