1 /* File: icon.c */
2
3 /* Purpose: icon stuff */
4
5 /*
6 * Copyright (c) 1997-2001 Tim Baker
7 *
8 * This software may be copied and distributed for educational, research, and
9 * not for profit purposes provided that this copyright and statement are
10 * included in all such copies.
11 */
12
13 #include "tnb.h"
14 #include "icon.h"
15
16 unsigned char *g_palette_rgb;
17
18 t_icon_data *g_icon_data; /* Array of icon types */
19 int g_icon_data_count = 0; /* Number of icon types */
20 Tcl_HashTable g_icon_table; /* Hash table for icon types */
21 long g_icon_length = 0; /* Length in bytes of one icon */
22 int g_icon_size = 0; /* Icon dimensions (16, 24 or 32) */
23 int g_icon_depth = 0; /* Icon depth (8, 16 or 24 bpp) */
24 int g_pixel_size; /* Num bytes per pixel (1, 2, 3 or 4) */
25 int g_icon_pixels; /* Num pixels per icon (16x16, 24x24, 32x32) */
26
27
28 int *g_background = NULL;
29
30 bool g_icon_map_changed = FALSE;
31
32
init_palette(void)33 void init_palette(void)
34 {
35 if (Palette_Init(g_interp) != TCL_OK)
36 quit(Tcl_GetStringResult(g_interp));
37
38 g_palette_rgb = Palette_GetRGB();
39 }
40
41
42 /*
43 *
44 */
Icon_AddType(t_icon_data * data)45 static void Icon_AddType(t_icon_data *data)
46 {
47 int new;
48 t_icon_data iconData, *icon_data_ptr = &iconData;
49 Tcl_HashEntry *hPtr;
50 memset(icon_data_ptr, 0, sizeof(t_icon_data));
51 icon_data_ptr->desc = string_make(data->desc);
52 icon_data_ptr->icon_count = data->icon_count;
53 icon_data_ptr->icon_data = data->icon_data;
54 icon_data_ptr->depth = data->depth;
55 icon_data_ptr->bypp = data->bypp;
56 icon_data_ptr->width = data->width;
57 icon_data_ptr->height = data->height;
58 icon_data_ptr->pitch = data->pitch;
59 icon_data_ptr->length = data->length;
60 icon_data_ptr->pixels = data->pixels;
61
62 g_icon_data = Array_Append(g_icon_data, &g_icon_data_count,
63 sizeof(t_icon_data), icon_data_ptr);
64
65 hPtr = Tcl_CreateHashEntry(&g_icon_table, data->desc, &new);
66 Tcl_SetHashValue(hPtr, (ClientData) (g_icon_data_count - 1));
67 }
68
69
70 /*
71 * Initialize the icon environment. This should be called once with
72 * the desired dimensions of the icons to use (16x16, 24x24 or 32x32).
73 */
init_icons(int size,int depth)74 void init_icons(int size, int depth)
75 {
76 int i, n, y, x, y2, x2;
77 t_assign_icon assign;
78 t_icon_data icon_data, *icon_data_ptr = &icon_data;
79 unsigned char *rgb = Colormap_GetRGB();
80
81 /* Initialize the Icon library */
82 if (Icon_Init(g_interp, size, depth) != TCL_OK)
83 {
84 quit(Tcl_GetStringFromObj(Tcl_GetObjResult(g_interp), NULL));
85 }
86
87 /*
88 * The TYPE_NONE/"none" type icon is a single masked icon with an empty
89 * mask. It is suitable for equipment displays when no item is present
90 * in a slot.
91 */
92 icon_data_ptr->desc = "none";
93 icon_data_ptr->icon_count = 1;
94 C_MAKE(icon_data_ptr->icon_data, g_icon_length, byte);
95 for (i = 0; i < g_icon_length; i++)
96 {
97 icon_data_ptr->icon_data[i] = 0x00;
98 }
99
100 icon_data_ptr->depth = g_icon_depth;
101 icon_data_ptr->bypp = g_pixel_size;
102 icon_data_ptr->width = g_icon_size;
103 icon_data_ptr->height = g_icon_size;
104 icon_data_ptr->pitch = g_icon_size * g_pixel_size;
105 icon_data_ptr->length = g_icon_size * g_icon_size * g_pixel_size;
106 icon_data_ptr->pixels = g_icon_size * g_icon_size;
107
108 Icon_AddType(icon_data_ptr);
109
110 for (i = 0; i < g_icon_length; i++)
111 {
112 if (g_icon_depth != 8)
113 icon_data_ptr->icon_data[i] = 0; /* Black (RGB 0,0,0) */
114 else
115 icon_data_ptr->icon_data[i] = COLORMAP_BLACK;
116 }
117
118 /*
119 * The TYPE_BLANK/"blank" icon type is a single black unmasked icon
120 */
121 icon_data_ptr->desc = "blank";
122 icon_data_ptr->icon_count = 1;
123 C_MAKE(icon_data_ptr->icon_data, g_icon_length, byte);
124 for (i = 0; i < g_icon_length; i++)
125 {
126 if (g_icon_depth != 8)
127 icon_data_ptr->icon_data[i] = 0; /* Black (RGB 0,0,0) */
128 else
129 icon_data_ptr->icon_data[i] = COLORMAP_BLACK;
130 }
131
132 icon_data_ptr->depth = g_icon_depth;
133 icon_data_ptr->bypp = g_pixel_size;
134 icon_data_ptr->width = g_icon_size;
135 icon_data_ptr->height = g_icon_size;
136 icon_data_ptr->pitch = g_icon_size * g_pixel_size;
137 icon_data_ptr->length = g_icon_size * g_icon_size * g_pixel_size;
138 icon_data_ptr->pixels = g_icon_size * g_icon_size;
139
140 Icon_AddType(icon_data_ptr);
141
142 /*
143 * The TYPE_DEFAULT/"default" icon type is a single multicolored
144 * unmasked icon. If we see it, it probably means we forgot to
145 * assign an icon to something.
146 */
147 icon_data_ptr->desc = "default";
148 icon_data_ptr->icon_count = 1;
149 C_MAKE(icon_data_ptr->icon_data, g_icon_length, byte);
150 n = 0, y2 = 0;
151 for (y = 0; y < 16; y++)
152 {
153 int dy = 0;
154 if (g_icon_size == 24)
155 {
156 if (!(y & 1)) dy++;
157 }
158 if (g_icon_size == 32) dy++;
159 x2 = 0;
160 for (x = 0; x < 16; x++)
161 {
162 int dx = 0;
163 if (g_icon_size == 24)
164 {
165 if (!(x & 1)) dx++;
166 }
167 if (g_icon_size == 32) dx++;
168 PixelSet_RGB(icon_data_ptr->icon_data + (x2 * g_pixel_size) + (y2 * g_icon_size * g_pixel_size),
169 rgb[0], rgb[1], rgb[2], g_pixel_size);
170 PixelSet_RGB(icon_data_ptr->icon_data + ((x2 + dx) * g_pixel_size) + (y2 * g_icon_size * g_pixel_size),
171 rgb[0], rgb[1], rgb[2], g_pixel_size);
172 PixelSet_RGB(icon_data_ptr->icon_data + (x2 * g_pixel_size) + ((y2 + dy) * g_icon_size * g_pixel_size),
173 rgb[0], rgb[1], rgb[2], g_pixel_size);
174 PixelSet_RGB(icon_data_ptr->icon_data + ((x2 + dx) * g_pixel_size) + ((y2 + dy) * g_icon_size * g_pixel_size),
175 rgb[0], rgb[1], rgb[2], g_pixel_size);
176 rgb += 3;
177
178 n++;
179 x2 += dx ? 2 : 1;
180 }
181 y2 += dy ? 2 : 1;
182 }
183
184 icon_data_ptr->depth = g_icon_depth;
185 icon_data_ptr->bypp = g_pixel_size;
186 icon_data_ptr->width = g_icon_size;
187 icon_data_ptr->height = g_icon_size;
188 icon_data_ptr->pitch = g_icon_size * g_pixel_size;
189 icon_data_ptr->length = g_icon_size * g_icon_size * g_pixel_size;
190 icon_data_ptr->pixels = g_icon_size * g_icon_size;
191
192 Icon_AddType(icon_data_ptr);
193
194
195 assign.type = ICON_TYPE_DEFAULT;
196 assign.index = 0;
197
198
199 /*
200 * When a feature is masked, or a masked icon is drawn on
201 * a feature, we may use the icon assigned to a different feature
202 * as the background.
203 */
204 C_MAKE(g_background, z_info->f_max, int);
205
206 /* Clear the color hash table */
207 Palette_ResetHash();
208
209 if (init_widget(g_interp, g_icon_depth) != TCL_OK)
210 quit(Tcl_GetStringFromObj(Tcl_GetObjResult(g_interp), NULL));
211
212 /* if (CanvasWidget_Init(g_interp) != TCL_OK)
213 quit(Tcl_GetStringFromObj(Tcl_GetObjResult(g_interp), NULL)); */
214 }
215
216
217 #include <limits.h>
218 #ifndef USHRT_MAX
219 #define USHRT_MAX 65535
220 #endif
221
222 int PixelPtrToLong(IconPtr p, int bypp);
223 void PixelLongToPtr(IconPtr dst, int pixel, int bypp);
224
225 /* Hack -- Standard 16 "term" colors. User should be able to change */
226 int g_term_palette[16] = {255, 0, 250, 17, 217, 196, 199, 101, 129,
227 247, 30, 5, 35, 185, 180, 52};
228
229 /* Actual 8/16/24 pixel values for above */
230 unsigned long g_term_colormap[16];
231
232
InitPixelSize(Tcl_Interp * interp)233 static int InitPixelSize(Tcl_Interp *interp)
234 {
235 BitmapType bitmap;
236
237 bitmap.width = bitmap.height = 10;
238 bitmap.depth = g_icon_depth;
239 Bitmap_New(interp, &bitmap);
240 g_pixel_size = bitmap.pixelSize;
241 Bitmap_Delete(&bitmap);
242
243 return TCL_OK;
244 }
245
246 RGBInfo g_rgbi;
247
CountBits(unsigned long mask)248 static int CountBits(unsigned long mask)
249 {
250 int n;
251
252 for (n = 0; mask != 0; mask &= mask - 1)
253 n++;
254 return n;
255 }
256
InitRGBInfo(Tcl_Interp * interp)257 static void InitRGBInfo(Tcl_Interp *interp)
258 {
259 Tk_Window tkwin = Tk_MainWindow(interp);
260 Visual *visual = Tk_Visual(tkwin);
261
262 g_rgbi.red_mask = visual->red_mask;
263 g_rgbi.green_mask = visual->green_mask;
264 g_rgbi.blue_mask = visual->blue_mask;
265
266 #ifdef PLATFORM_WIN
267 /* XXX Always 5-5-5 */
268 g_rgbi.red_mask = 0x7c00;
269 g_rgbi.green_mask = 0x03e0;
270 g_rgbi.blue_mask = 0x001f;
271 #endif
272
273 g_rgbi.red_count = CountBits(g_rgbi.red_mask);
274 g_rgbi.green_count = CountBits(g_rgbi.green_mask);
275 g_rgbi.blue_count = CountBits(g_rgbi.blue_mask);
276
277 g_rgbi.red_shift = g_rgbi.red_count + g_rgbi.green_count + g_rgbi.blue_count - 8;
278 g_rgbi.green_shift = g_rgbi.green_count + g_rgbi.blue_count - 8;
279 g_rgbi.blue_shift = -(g_rgbi.blue_count - 8);
280
281 g_rgbi.extra = ~(g_rgbi.red_mask | g_rgbi.green_mask | g_rgbi.blue_mask);
282 }
283
284
SetPix8(unsigned char * p,int r,int g,int b)285 static void SetPix8(unsigned char *p, int r, int g, int b)
286 {
287 /* NOTE: Not Colormap */
288 *p = Palette_RGB2Index(r, g, b);
289 }
290
SetPix16(unsigned char * p,int r,int g,int b)291 void SetPix16(unsigned char *p, int r, int g, int b)
292 {
293 int r2 = (r << g_rgbi.red_shift) & g_rgbi.red_mask;
294 int g2 = (g << g_rgbi.green_shift) & g_rgbi.green_mask;
295 int b2 = (b >> g_rgbi.blue_shift) & g_rgbi.blue_mask;
296
297 *((unsigned short *) p) = g_rgbi.extra | r2 | g2 | b2;
298 }
299
SetPix24(unsigned char * p,int r,int g,int b)300 static void SetPix24(unsigned char *p, int r, int g, int b)
301 {
302 *p++ = b;
303 *p++ = g;
304 *p++ = r;
305 if (g_pixel_size == 4)
306 *p++ = 0xFF;
307 }
308
PixelSet_RGB(IconPtr dst,int r,int g,int b,int bypp)309 void PixelSet_RGB(IconPtr dst, int r, int g, int b, int bypp)
310 {
311 switch (bypp)
312 {
313 case 1:
314 SetPix8(dst, r, g, b);
315 break;
316 case 2:
317 SetPix16(dst, r, g, b);
318 break;
319 case 3:
320 case 4:
321 SetPix24(dst, r, g, b);
322 break;
323 }
324 }
325
PixelLongToPtr(IconPtr p,int pixel,int bypp)326 void PixelLongToPtr(IconPtr p, int pixel, int bypp)
327 {
328 switch (bypp)
329 {
330 case 1:
331 *p = (unsigned char) pixel;
332 break;
333 case 2:
334 *((unsigned short *) p) = pixel & 0xFFFF;
335 break;
336 case 3:
337 {
338 unsigned char *p2 = (unsigned char *) &pixel;
339 *p++ = *p2++;
340 *p++ = *p2++;
341 *p++ = *p2++;
342 break;
343 }
344 case 4:
345 *((unsigned long *) p) = pixel;
346 break;
347 }
348 }
349
PixelPtrToLong(IconPtr p,int bypp)350 int PixelPtrToLong(IconPtr p, int bypp)
351 {
352 switch (bypp)
353 {
354 case 1:
355 return *p;
356 case 2:
357 return *(unsigned short *) p;
358 case 3:
359 return p[0] + (p[1] << 8) + (p[2] << 16); /* ??? */
360 case 4:
361 return *(int *) p;
362 }
363 return 0;
364 }
365
366
367 /*
368 * objcmd_icon --
369 */
objcmd_icon(ClientData dummy,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])370 static int objcmd_icon(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
371 {
372 static cptr cmdOption[] = {"size", NULL};
373 enum {IDX_SIZE};
374 int option;
375 Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
376
377 /* Hack - ignore parameter */
378 (void) dummy;
379
380 /* Required number of arguments */
381 if (objc < 2)
382 {
383 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
384 return TCL_ERROR;
385 }
386
387 /* Get requested option */
388 if (Tcl_GetIndexFromObj(interp, objv[1], cmdOption, "option", 0,
389 &option) != TCL_OK)
390 {
391 return TCL_ERROR;
392 }
393
394 switch (option)
395 {
396 case IDX_SIZE: /* size */
397 Tcl_SetIntObj(resultPtr, g_icon_size);
398 break;
399 }
400
401 /* Success */
402 return TCL_OK;
403 }
404
405
406 /*
407 * Initialization.
408 */
Icon_Init(Tcl_Interp * interp,int size,int depth)409 int Icon_Init(Tcl_Interp *interp, int size, int depth)
410 {
411 /* Only initialize once */
412 if (g_icon_size != 0) return TCL_OK;
413
414 /* Require a known icon size */
415 if ((size != 16) && (size != 24) && (size != 32))
416 {
417 Tcl_SetStringObj(Tcl_GetObjResult(interp),
418 format("invalid icon size \"%d\": must be 16, 24 or 32", size), -1);
419 return TCL_ERROR;
420 }
421
422 /* Require a known icon depth */
423 if ((depth != 8) && (depth != 16) && (depth != 24))
424 {
425 Tcl_SetStringObj(Tcl_GetObjResult(interp),
426 format("invalid icon depth \"%d\": must be 8, 16 or 24", depth), -1);
427 return TCL_ERROR;
428 }
429
430 /* Remember the requested icon size */
431 g_icon_size = size;
432
433 /* Remember the requested icon depth */
434 g_icon_depth = depth;
435
436 if (InitPixelSize(interp) != TCL_OK)
437 {
438 return TCL_ERROR;
439 }
440
441 /* Remember number of pixels in an icon */
442 g_icon_pixels = size * size;
443
444 /* Remember the number of bytes in an icon */
445 g_icon_length = g_icon_pixels * g_pixel_size;
446
447 /***** RETURN ERROR IF PALETTE NOT INITIALIZED *****/
448
449 g_palette_rgb = Palette_GetRGB();
450
451 if (g_icon_depth == 16) InitRGBInfo(interp);
452
453
454
455
456 /* New block here */
457 {
458 int i, paletteIndex;
459 for (i = 0; i < 16; i++)
460 {
461 paletteIndex = g_term_palette[i];
462 switch (g_icon_depth)
463 {
464 case 8:
465 g_term_colormap[i] = g_palette2colormap[paletteIndex];
466 break;
467 case 16:
468 {
469 unsigned short pix16;
470 unsigned char *rgb = &g_palette_rgb[paletteIndex * 3];
471 SetPix16((unsigned char *) &pix16, rgb[0], rgb[1], rgb[2]);
472 g_term_colormap[i] = pix16;
473 break;
474 }
475 case 24:
476 {
477 unsigned char *rgb = &g_palette_rgb[paletteIndex * 3];
478 unsigned char *pix24 = (unsigned char *) &g_term_colormap[i];
479 SetPix24(pix24 + 1, rgb[0], rgb[1], rgb[2]);
480 break;
481 }
482 }
483 }
484 }
485
486 /*
487 * This is an array of t_icon_data types, which specify
488 * the icon data and optional mask data for each type of
489 * icon. Icon types are defined through the "icon createtype"
490 * command.
491 */
492 MAKE(g_icon_data, t_icon_data);
493 g_icon_data_count = 0;
494
495 /*
496 * This hash table maps symbolic names of icon types (as defined
497 * through the "icon createtype" command) to indexes into
498 * the g_icon_data[] array above.
499 */
500 Tcl_InitHashTable(&g_icon_table, TCL_STRING_KEYS);
501
502 Tcl_CreateObjCommand(interp, "icon", objcmd_icon, NULL, NULL);
503
504 return TCL_OK;
505 }
506
Icon_Exit(void)507 void Icon_Exit(void)
508 {
509 int i;
510
511 if (g_icon_size == 0) return;
512
513 /* Check each icon type */
514 for (i = 0; i < g_icon_data_count; i++)
515 {
516 t_icon_data *iconDataPtr = &g_icon_data[i];
517
518 /* Help the memory debugger */
519 if (iconDataPtr->icon_data)
520 FREE(iconDataPtr->icon_data);
521 }
522 }
523