1 /* File: util-dll.c */
2
3 /* Purpose: misc 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
15 #include <limits.h>
16 #ifndef USHRT_MAX
17 #define USHRT_MAX 65535
18 #endif
19
20 #define MAX_DELTA (255 * 6)
21 #define MAX_COLOR_ENTRY 1021
22
23 #ifdef HAVE_TKFONT_H
24 #include <tkFont.h>
25 #else /* HAVE_TKFONT_H */
26
27 typedef struct TkFontAttributes {
28 Tk_Uid family; /* Font family, or NULL to represent
29 * plaform-specific default system font. */
30 int size; /* Pointsize of font, 0 for default size, or
31 * negative number meaning pixel size. */
32 int weight; /* Weight flag; see below for def'n. */
33 int slant; /* Slant flag; see below for def'n. */
34 int underline; /* Non-zero for underline font. */
35 int overstrike; /* Non-zero for overstrike font. */
36 } TkFontAttributes;
37
38 #define TK_FW_NORMAL 0
39 #define TK_FW_BOLD 1
40
41 #define TK_FS_ROMAN 0
42 #define TK_FS_ITALIC 1
43
44 typedef struct TkFontMetrics {
45 int ascent; /* From baseline to top of font. */
46 int descent; /* From baseline to bottom of font. */
47 int maxWidth; /* Width of widest character in font. */
48 int fixed; /* Non-zero if this is a fixed-width font,
49 * 0 otherwise. */
50 } TkFontMetrics;
51
52
53 typedef struct TkFont {
54 /*
55 * Fields used and maintained exclusively by generic code.
56 */
57
58 int resourceRefCount; /* Number of active uses of this font (each
59 * active use corresponds to a call to
60 * Tk_AllocFontFromTable or Tk_GetFont).
61 * If this count is 0, then this TkFont
62 * structure is no longer valid and it isn't
63 * present in a hash table: it is being
64 * kept around only because there are objects
65 * referring to it. The structure is freed
66 * when resourceRefCount and objRefCount
67 * are both 0. */
68 int objRefCount; /* The number of Tcl objects that reference
69 * this structure. */
70 Tcl_HashEntry *cacheHashPtr;/* Entry in font cache for this structure,
71 * used when deleting it. */
72 Tcl_HashEntry *namedHashPtr;/* Pointer to hash table entry that
73 * corresponds to the named font that the
74 * tkfont was based on, or NULL if the tkfont
75 * was not based on a named font. */
76 Screen *screen; /* The screen where this font is valid. */
77 int tabWidth; /* Width of tabs in this font (pixels). */
78 int underlinePos; /* Offset from baseline to origin of
79 * underline bar (used for drawing underlines
80 * on a non-underlined font). */
81 int underlineHeight; /* Height of underline bar (used for drawing
82 * underlines on a non-underlined font). */
83
84 /*
85 * Fields used in the generic code that are filled in by
86 * platform-specific code.
87 */
88
89 Font fid; /* For backwards compatibility with XGCValues
90 * structures. Remove when TkGCValues is
91 * implemented. */
92 TkFontAttributes fa; /* Actual font attributes obtained when the
93 * the font was created, as opposed to the
94 * desired attributes passed in to
95 * TkpGetFontFromAttributes(). The desired
96 * metrics can be determined from the string
97 * that was used to create this font. */
98 TkFontMetrics fm; /* Font metrics determined when font was
99 * created. */
100 struct TkFont *nextPtr; /* Points to the next TkFont structure with
101 * the same name. All fonts with the
102 * same name (but different displays) are
103 * chained together off a single entry in
104 * a hash table. */
105 } TkFont;
106
107 #endif /* !HAVE_TKFONT_H */
108
109 /* Structure for a hash table used by rgb2index() */
110 typedef struct
111 {
112 int valid; /* The hash-table entry is valid */
113 u32b pixel; /* an RGB pixel value */
114 int index; /* closest matching palette index for 'pixel' */
115 } t_color_entry;
116
117 typedef struct IndexedColor IndexedColor;
118 struct IndexedColor
119 {
120 byte rgb[256 * 3];
121 t_color_entry hash[MAX_COLOR_ENTRY];
122 void *platData;
123 };
124
125 static IndexedColor g_palette;
126 static bool Palette_Initialized = 0;
127
128 int g_palette_black = 255;
129 int g_palette_white = 0;
130 int g_colormap_black;
131 int g_colormap_white;
132
133 byte g_palette2colormap[256];
134
135 /*
136 * Append an element to an array
137 */
Array_Append(void * array_ptr,int * count,int elem_size,void * elem_ptr)138 void *Array_Append(void *array_ptr, int *count, int elem_size,
139 void *elem_ptr)
140 {
141 char *ap = array_ptr;
142 int n = (*count) + 1;
143
144 ap = Tcl_Realloc(ap, n * elem_size);
145 (void) memcpy(ap + (n - 1) * elem_size, elem_ptr, elem_size);
146 (*count) = n;
147 return ap;
148 }
149
150 /*
151 * Insert an element in an array
152 */
Array_Insert(void * array_ptr,int * count,int elem_size,int index)153 void *Array_Insert(void *array_ptr, int *count, int elem_size,
154 int index)
155 {
156 char *ap = array_ptr;
157 int n = (*count) + 1;
158
159 if (index < 0) index = 0;
160 if (index >= n) index = n - 1;
161
162 ap = Tcl_Realloc(ap, n * elem_size);
163 if (index != n - 1)
164 {
165 (void) memcpy(ap + (index + 1) * elem_size,
166 ap + index * elem_size,
167 (n - index - 1) * elem_size);
168 }
169 else
170 {
171 memset(ap + index * elem_size, 0, elem_size);
172 }
173 (*count) = n;
174 return ap;
175 }
176
177 /*
178 * Delete an element from an array
179 */
Array_Delete(void * array_ptr,int * count,int elem_size,int index)180 void *Array_Delete(void *array_ptr, int *count, int elem_size,
181 int index)
182 {
183 char *ap = array_ptr;
184 int i, n = (*count) - 1;
185
186 if (index < 0) index = 0;
187 if (index > n) index = n;
188
189 if (index != n)
190 {
191 (void) memcpy(ap + index * elem_size,
192 ap + (index + 1) * elem_size,
193 (n - index) * elem_size);
194 }
195
196 /* Zero the trailing slot to catch errors */
197 for (i = 0; i < elem_size; i++)
198 {
199 ap[n * elem_size + i] = 0;
200 }
201
202 (*count) = n;
203 return (void *) Tcl_Realloc(ap, n * elem_size);
204 }
205
IndexedColor_ResetHash(IndexedColor * idc)206 static void IndexedColor_ResetHash(IndexedColor *idc)
207 {
208 int i;
209
210 for (i = 0; i < 256; i++)
211 {
212 idc->hash[i].valid = 0;
213 }
214 }
215
216 /*
217 * Returns the nearest matching palette index for the given
218 * RGB values.
219 */
IndexedColor_RGB2Index(IndexedColor * idc,unsigned char r,unsigned char g,unsigned char b)220 static int IndexedColor_RGB2Index(IndexedColor *idc, unsigned char r, unsigned char g, unsigned char b)
221 {
222 int i, diff, index, max;
223 unsigned char *col;
224 unsigned long pixel;
225 t_color_entry *entry;
226
227 /* Calculate the pixel value */
228 pixel = (r << 16) | (g << 8) | b;
229
230 /* Hash the pixel value */
231 entry = &idc->hash[pixel % MAX_COLOR_ENTRY];
232
233 /* We already calculated the palette index */
234 if (entry->valid && (entry->pixel == pixel))
235 {
236 /* Return the palette index */
237 return entry->index;
238 }
239
240 index = 0;
241 max = MAX_DELTA;
242
243 col = idc->rgb;
244
245 /* Check each palette entry */
246 for (i = 0; i < 256; i++)
247 {
248 /* Work out the 'difference' between the colours */
249
250 diff = abs(r - col[0]);
251 diff += abs(g - col[1]);
252 diff += abs(b - col[2]);
253
254 /* Multiply by the 'colour factor' */
255 diff *= 3;
256
257 /* Add in the effects of brightness */
258 diff += abs(b + r + g - col[0] - col[1] - col[2]);
259
260 col += 3;
261
262 /* This palette entry is a better match than any other so far */
263 if (diff < max)
264 {
265 /* Remember the palette index */
266 index = i;
267
268 /* Remember the minimum difference */
269 max = diff;
270 }
271 }
272
273 /* Remember the hash table entry info */
274 entry->pixel = pixel;
275 entry->index = index;
276 entry->valid = 1;
277
278 /* Return the palette index */
279 return index;
280 }
281
282 /* set $index ?$color? */
objcmd_palette_set(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])283 static int objcmd_palette_set(ClientData clientData, Tcl_Interp *interp, int objc,
284 Tcl_Obj *CONST objv[])
285 {
286 CommandInfo *infoCmd = (CommandInfo *) clientData;
287 int objC = objc - infoCmd->depth;
288 Tcl_Obj *CONST *objV = objv + infoCmd->depth;
289 char buf[20];
290 int i, r, g, b;
291
292 if (Tcl_GetIntFromObj(interp, objV[1], &i) != TCL_OK)
293 {
294 return TCL_ERROR;
295 }
296 if ((i < 0) || (i >= 256))
297 {
298 return TCL_ERROR;
299 }
300
301 if (objC == 3)
302 {
303 XColor *xColorPtr = Tk_AllocColorFromObj(interp, Tk_MainWindow(interp), objV[2]);
304 if (xColorPtr == NULL)
305 {
306 return TCL_ERROR;
307 }
308 g_palette.rgb[i * 3] = xColorPtr->red / 255;
309 g_palette.rgb[i * 3 + 1] = xColorPtr->green / 255;
310 g_palette.rgb[i * 3 + 2] = xColorPtr->blue / 255;
311 Tk_FreeColor(xColorPtr);
312 return TCL_OK;
313 }
314
315 r = g_palette.rgb[i * 3];
316 g = g_palette.rgb[i * 3 + 1];
317 b = g_palette.rgb[i * 3 + 2];
318 strnfmt(buf, 20, "#%02X%02X%02X", r, g, b);
319 Tcl_SetResult(interp, buf, TCL_VOLATILE);
320
321 return TCL_OK;
322 }
323
324 static CommandInit commandInit[] = {
325 {0, "palette", 0, 0, NULL, NULL, (ClientData) 0},
326 {1, "set", 2, 3, "?color?", objcmd_palette_set, (ClientData) 0},
327 {0, NULL, 0, 0, NULL, NULL, 0}
328 };
329
330 /* Uniform colour table */
331 static byte def_pal1[6] = {255, 204, 153, 102, 51, 0};
332 static byte def_pal2[10] = {238, 221, 187, 170, 136, 119, 85, 68, 34, 17};
333
Palette_Init(Tcl_Interp * interp)334 int Palette_Init(Tcl_Interp *interp)
335 {
336 int i, j, k;
337 unsigned char *rgb;
338
339 if (Palette_Initialized) return TCL_OK;
340
341 rgb = g_palette.rgb;
342 g_palette.platData = NULL;
343
344 /* Create colour cube */
345 for (i = 0; i < 6; i++)
346 {
347 for (j = 0; j < 6; j++)
348 {
349 for (k = 0; k < 6; k++)
350 {
351 /* Write this color to the array */
352 *rgb++ = def_pal1[i];
353 *rgb++ = def_pal1[j];
354 *rgb++ = def_pal1[k];
355 }
356 }
357 }
358
359 /* Create primary colours */
360 for (i = 0; i < 10; i++)
361 {
362 *rgb++ = def_pal2[i];
363 *rgb++ = 0;
364 *rgb++ = 0;
365 }
366 for (i = 0; i < 10; i++)
367 {
368 *rgb++ = 0;
369 *rgb++ = def_pal2[i];
370 *rgb++ = 0;
371 }
372 for (i = 0; i < 10; i++)
373 {
374 *rgb++ = 0;
375 *rgb++ = 0;
376 *rgb++ = def_pal2[i];
377 }
378
379 /* Create greys */
380 for (i = 0; i < 10; i++)
381 {
382 *rgb++ = def_pal2[i];
383 *rgb++ = def_pal2[i];
384 *rgb++ = def_pal2[i];
385 }
386
387 g_palette.platData = Plat_PaletteInit(g_palette.rgb);
388
389 (void) CommandInfo_Init(interp, commandInit, NULL);
390
391 Palette_ResetHash();
392
393 Palette_Initialized = TRUE;
394
395 Colormap_Init(interp);
396
397 return TCL_OK;
398 }
399
400
Palette_ResetHash(void)401 void Palette_ResetHash(void)
402 {
403 IndexedColor_ResetHash(&g_palette);
404 }
405
406 /*
407 * Returns the nearest matching palette index for the given
408 * RGB values.
409 */
Palette_RGB2Index(unsigned char r,unsigned char g,unsigned char b)410 int Palette_RGB2Index(unsigned char r, unsigned char g, unsigned char b)
411 {
412 return IndexedColor_RGB2Index(&g_palette, r, g, b);
413 }
414
415
416 #ifdef PLATFORM_WIN
417
Palette_GetHPal(void)418 void *Palette_GetHPal(void)
419 {
420 return g_palette.platData; /* HPALETTE */
421 }
422
423 #endif /* PLATFORM_WIN */
424
Palette_GetRGB(void)425 unsigned char *Palette_GetRGB(void)
426 {
427 return g_palette.rgb;
428 }
429
430
ExtToUtf_NewStringObj(CONST char * bytes,int length)431 Tcl_Obj *ExtToUtf_NewStringObj(CONST char *bytes, int length)
432 {
433 char *utfString;
434 Tcl_DString utfDString;
435 Tcl_Obj *objResult;
436
437 utfString = Tcl_ExternalToUtfDString(NULL, bytes, length, &utfDString);
438 objResult = Tcl_NewStringObj(utfString, Tcl_DStringLength(&utfDString));
439 Tcl_DStringFree(&utfDString);
440 return objResult;
441 }
442
ExtToUtf_SetResult(Tcl_Interp * interp,cptr string)443 void ExtToUtf_SetResult(Tcl_Interp *interp, cptr string)
444 {
445 char *utfString;
446 Tcl_DString utfDString;
447
448 utfString = Tcl_ExternalToUtfDString(NULL, string, -1, &utfDString);
449 Tcl_SetResult(interp, utfString, TCL_VOLATILE);
450 Tcl_DStringFree(&utfDString);
451 }
452
UtfToExt_TranslateFileName(Tcl_Interp * interp,char * utfPath,Tcl_DString * extDStringPtr)453 char *UtfToExt_TranslateFileName(Tcl_Interp *interp, char *utfPath, Tcl_DString *extDStringPtr)
454 {
455 char *extString, *utfString;
456 Tcl_DString utfDString;
457 int utfLen;
458
459 utfString = Tcl_TranslateFileName(interp, utfPath, &utfDString);
460 if (utfString == NULL) return NULL;
461 utfLen = Tcl_DStringLength(&utfDString);
462 extString = Tcl_UtfToExternalDString(NULL, utfString, utfLen, extDStringPtr);
463 Tcl_DStringFree(&utfDString);
464 return extString;
465 }
466
467 static IndexedColor g_colormap;
468 unsigned char *g_colormap_rgb;
469
Colormap_Init(Tcl_Interp * interp)470 int Colormap_Init(Tcl_Interp *interp)
471 {
472 #ifdef PLATFORM_X11
473 Tk_Window tkwin = Tk_MainWindow(interp);
474 Display *display = Tk_Display(tkwin);
475 Colormap colormap = Tk_Colormap(tkwin); /* DefaultColormap() */
476 XColor xColor;
477 #endif
478 int i, k, r, g, b;
479
480 IndexedColor_ResetHash(&g_colormap);
481
482 #ifdef PLATFORM_X11
483 if (Tk_Depth(tkwin) == 8)
484 {
485 /*
486 * Allocate each color in the colormap, to prevent the colormap
487 * entries from changing.
488 */
489 for (i = 0; i < 256; i++)
490 {
491 xColor.pixel = i;
492 XQueryColor(display, colormap, &xColor);
493 (void) Tk_GetColorByValue(tkwin, &xColor);
494 }
495 }
496 #endif /* PLATFORM_X11 */
497
498 for (i = 0; i < 256; i++)
499 {
500 r = g_palette.rgb[i * 3 + 0];
501 g = g_palette.rgb[i * 3 + 1];
502 b = g_palette.rgb[i * 3 + 2];
503
504 #ifdef PLATFORM_X11
505 if (Tk_Depth(tkwin) == 8)
506 {
507 /* Get the XColor at this location in the colormap */
508 xColor.pixel = i;
509 XQueryColor(display, colormap, &xColor);
510
511 /* Convert RGB values to 0-255 */
512 r = xColor.red / 255;
513 g = xColor.green / 255;
514 b = xColor.blue / 255;
515 }
516 #endif /* PLATFORM_X11 */
517
518 /* Remember RGB values at this colormap index */
519 g_colormap.rgb[i * 3 + 0] = r;
520 g_colormap.rgb[i * 3 + 1] = g;
521 g_colormap.rgb[i * 3 + 2] = b;
522 }
523
524 for (i = 0; i < 256; i++)
525 {
526 /* Get the RGB values at this palette index */
527 r = g_palette.rgb[i * 3 + 0];
528 g = g_palette.rgb[i * 3 + 1];
529 b = g_palette.rgb[i * 3 + 2];
530
531 /* Find the closest color in the colormap */
532 k = Colormap_RGB2Index(r, g, b);
533
534 /* Map palette index -> colormap index */
535 g_palette2colormap[i] = k;
536 }
537
538 /* Get the black and white pixels */
539 g_colormap_black = PALETTE_BLACK;
540 g_colormap_white = PALETTE_WHITE;
541
542 #ifdef PLATFORM_X11
543 if (Tk_Depth(tkwin) == 8)
544 {
545 g_colormap_black = BlackPixelOfScreen(Tk_Screen(tkwin));
546 g_colormap_white = WhitePixelOfScreen(Tk_Screen(tkwin));
547 }
548 #endif /* PLATFORM_X11 */
549
550 g_colormap_rgb = g_colormap.rgb;
551
552 return TCL_OK;
553 }
554
Colormap_GetRGB(void)555 unsigned char *Colormap_GetRGB(void)
556 {
557 return g_colormap.rgb;
558 }
559
Colormap_RGB2Index(unsigned char r,unsigned char g,unsigned char b)560 int Colormap_RGB2Index(unsigned char r, unsigned char g, unsigned char b)
561 {
562 return IndexedColor_RGB2Index(&g_colormap, r, g, b);
563 }
564
565 /*
566 * Return a "standardized" string describing a font.
567 */
objcmd_fontdesc(ClientData dummy,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])568 int objcmd_fontdesc(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
569 {
570 Tk_Font tkfont;
571 TkFont *fontPtr;
572 char buf[1024];
573
574 /* Hack - ignore unused parameter */
575 (void) dummy;
576
577 if (objc != 2)
578 {
579 Tcl_WrongNumArgs(interp, 1, objv, "font");
580 return TCL_ERROR;
581 }
582
583 tkfont = Tk_AllocFontFromObj(interp, Tk_MainWindow(interp), objv[1]);
584 if (tkfont == NULL)
585 {
586 return TCL_ERROR;
587 }
588
589 fontPtr = (TkFont *) tkfont;
590
591 strnfmt(buf, 1024, "-family {%s} -size %d -weight %s -slant %s "
592 "-underline %d -overstrike %d",
593 fontPtr->fa.family, fontPtr->fa.size,
594 (fontPtr->fa.weight == TK_FW_BOLD) ? "bold" : "normal",
595 (fontPtr->fa.slant == TK_FS_ITALIC) ? "italic" : "roman",
596 fontPtr->fa.underline,
597 fontPtr->fa.overstrike);
598
599 Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1);
600
601 Tk_FreeFontFromObj(Tk_MainWindow(interp), objv[1]);
602
603 return TCL_OK;
604 }
605
606
607 cptr keyword_term_color[16] = {
608 "TERM_DARK",
609 "TERM_WHITE",
610 "TERM_SLATE",
611 "TERM_ORANGE",
612 "TERM_RED",
613 "TERM_GREEN",
614 "TERM_BLUE",
615 "TERM_UMBER",
616 "TERM_L_DARK",
617 "TERM_L_WHITE",
618 "TERM_VIOLET",
619 "TERM_YELLOW",
620 "TERM_L_RED",
621 "TERM_L_GREEN",
622 "TERM_L_BLUE",
623 "TERM_L_UMBER"
624 };
625
626
627 byte g_prompt_attr = TERM_WHITE;
628
629 /*
630 * Display a prompt in the "message line", but don't save it.
631 */
prompt_print(cptr str)632 void prompt_print(cptr str)
633 {
634 cptr attr = keyword_term_color[g_prompt_attr];
635
636 angtk_eval("angband_prompt", "set", str, attr, NULL);
637 }
638
639 /*
640 * Erase the "message line".
641 */
prompt_erase(void)642 void prompt_erase(void)
643 {
644 angtk_eval("angband_prompt", "wipe", NULL);
645 }
646
647 /*
648 * Display a formatted prompt, using "vstrnfmt()" and "prompt_print()".
649 */
prompt_format(cptr fmt,...)650 void prompt_format(cptr fmt, ...)
651 {
652 va_list vp;
653
654 char buf[1024];
655
656 /* Begin the Varargs Stuff */
657 va_start(vp, fmt);
658
659 /* Format the args, save the length */
660 (void)vstrnfmt(buf, 1024, fmt, &vp);
661
662 /* End the Varargs Stuff */
663 va_end(vp);
664
665 /* Display */
666 prompt_print(buf);
667 }
668
prompt_append(cptr str)669 void prompt_append(cptr str)
670 {
671 cptr attr = keyword_term_color[g_prompt_attr];
672
673 angtk_eval("angband_prompt", "append", str, attr, NULL);
674 }
675
prompt_open(cptr str)676 void prompt_open(cptr str)
677 {
678 cptr attr = keyword_term_color[g_prompt_attr];
679
680 angtk_eval("angband_prompt", "open", str, attr, NULL);
681 }
682
prompt_update(cptr str)683 void prompt_update(cptr str)
684 {
685 cptr attr = keyword_term_color[g_prompt_attr];
686
687 angtk_eval("angband_prompt", "update", str, attr, NULL);
688 }
689
690 /*
691 * Display a prompt, wait for a keypress.
692 */
any_more(cptr prompt)693 void any_more(cptr prompt)
694 {
695 bool old_quick = quick_messages;
696
697 /* Set the prompt */
698 if (!prompt)
699 prompt = "Hit any key to continue";
700
701 /* Set quick_messages so any key is accepted */
702 quick_messages = TRUE;
703
704 /* Display the message, wait for a response */
705 msgf(prompt);
706 message_flush();
707
708 /* Restore quick_messages */
709 quick_messages = old_quick;
710 }
711
ExtToUtf_SetArrayValueString(cptr varName,cptr field,cptr value)712 int ExtToUtf_SetArrayValueString(cptr varName, cptr field, cptr value)
713 {
714 Tcl_DString utfDString;
715 cptr utfString;
716
717 Tcl_ExternalToUtfDString(NULL, value, -1, &utfDString);
718 utfString = Tcl_DStringValue(&utfDString);
719 if (Tcl_SetVar2(g_interp, varName, field, utfString, TCL_LEAVE_ERR_MSG)
720 == NULL)
721 {
722 Tcl_DStringFree(&utfDString);
723 return TCL_ERROR;
724 }
725 Tcl_DStringFree(&utfDString);
726 return TCL_OK;
727 }
728
729
730