1 /*
2 * tkUtil.c --
3 *
4 * This file contains miscellaneous utility functions that are used by
5 * the rest of Tk, such as a function for drawing a focus highlight.
6 *
7 * Copyright (c) 1994 The Regents of the University of California.
8 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
9 *
10 * See the file "license.terms" for information on usage and redistribution of
11 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 */
13
14 #include "tkInt.h"
15
16 /*
17 * The structure below defines the implementation of the "statekey" Tcl
18 * object, used for quickly finding a mapping in a TkStateMap.
19 */
20
21 Tcl_ObjType tkStateKeyObjType = {
22 "statekey", /* name */
23 NULL, /* freeIntRepProc */
24 NULL, /* dupIntRepProc */
25 NULL, /* updateStringProc */
26 NULL /* setFromAnyProc */
27 };
28
29 /*
30 *--------------------------------------------------------------
31 *
32 * TkStateParseProc --
33 *
34 * This function is invoked during option processing to handle the
35 * "-state" and "-default" options.
36 *
37 * Results:
38 * A standard Tcl return value.
39 *
40 * Side effects:
41 * The state for a given item gets replaced by the state indicated in the
42 * value argument.
43 *
44 *--------------------------------------------------------------
45 */
46
47 int
TkStateParseProc(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,const char * value,char * widgRec,int offset)48 TkStateParseProc(
49 ClientData clientData, /* some flags.*/
50 Tcl_Interp *interp, /* Used for reporting errors. */
51 Tk_Window tkwin, /* Window containing canvas widget. */
52 const char *value, /* Value of option. */
53 char *widgRec, /* Pointer to record for item. */
54 int offset) /* Offset into item. */
55 {
56 int c;
57 int flags = PTR2INT(clientData);
58 size_t length;
59
60 register Tk_State *statePtr = (Tk_State *) (widgRec + offset);
61
62 if(value == NULL || *value == 0) {
63 *statePtr = TK_STATE_NULL;
64 return TCL_OK;
65 }
66
67 c = value[0];
68 length = strlen(value);
69
70 if ((c == 'n') && (strncmp(value, "normal", length) == 0)) {
71 *statePtr = TK_STATE_NORMAL;
72 return TCL_OK;
73 }
74 if ((c == 'd') && (strncmp(value, "disabled", length) == 0)) {
75 *statePtr = TK_STATE_DISABLED;
76 return TCL_OK;
77 }
78 if ((c == 'a') && (flags&1) && (strncmp(value, "active", length) == 0)) {
79 *statePtr = TK_STATE_ACTIVE;
80 return TCL_OK;
81 }
82 if ((c == 'h') && (flags&2) && (strncmp(value, "hidden", length) == 0)) {
83 *statePtr = TK_STATE_HIDDEN;
84 return TCL_OK;
85 }
86
87 Tcl_AppendResult(interp, "bad ", (flags&4)?"-default" : "state",
88 " value \"", value, "\": must be normal", NULL);
89 if (flags&1) {
90 Tcl_AppendResult(interp, ", active", NULL);
91 }
92 if (flags&2) {
93 Tcl_AppendResult(interp, ", hidden", NULL);
94 }
95 if (flags&3) {
96 Tcl_AppendResult(interp, ",", NULL);
97 }
98 Tcl_AppendResult(interp, " or disabled", NULL);
99 *statePtr = TK_STATE_NORMAL;
100 return TCL_ERROR;
101 }
102
103 /*
104 *--------------------------------------------------------------
105 *
106 * TkStatePrintProc --
107 *
108 * This function is invoked by the Tk configuration code to produce a
109 * printable string for the "-state" configuration option.
110 *
111 * Results:
112 * The return value is a string describing the state for the item
113 * referred to by "widgRec". In addition, *freeProcPtr is filled in with
114 * the address of a function to call to free the result string when it's
115 * no longer needed (or NULL to indicate that the string doesn't need to
116 * be freed).
117 *
118 * Side effects:
119 * None.
120 *
121 *--------------------------------------------------------------
122 */
123
124 char *
TkStatePrintProc(ClientData clientData,Tk_Window tkwin,char * widgRec,int offset,Tcl_FreeProc ** freeProcPtr)125 TkStatePrintProc(
126 ClientData clientData, /* Ignored. */
127 Tk_Window tkwin, /* Window containing canvas widget. */
128 char *widgRec, /* Pointer to record for item. */
129 int offset, /* Offset into item. */
130 Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with
131 * information about how to reclaim storage
132 * for return string. */
133 {
134 register Tk_State *statePtr = (Tk_State *) (widgRec + offset);
135
136 switch (*statePtr) {
137 case TK_STATE_NORMAL:
138 return "normal";
139 case TK_STATE_DISABLED:
140 return "disabled";
141 case TK_STATE_HIDDEN:
142 return "hidden";
143 case TK_STATE_ACTIVE:
144 return "active";
145 default:
146 return "";
147 }
148 }
149
150 /*
151 *--------------------------------------------------------------
152 *
153 * TkOrientParseProc --
154 *
155 * This function is invoked during option processing to handle the
156 * "-orient" option.
157 *
158 * Results:
159 * A standard Tcl return value.
160 *
161 * Side effects:
162 * The orientation for a given item gets replaced by the orientation
163 * indicated in the value argument.
164 *
165 *--------------------------------------------------------------
166 */
167
168 int
TkOrientParseProc(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,const char * value,char * widgRec,int offset)169 TkOrientParseProc(
170 ClientData clientData, /* some flags.*/
171 Tcl_Interp *interp, /* Used for reporting errors. */
172 Tk_Window tkwin, /* Window containing canvas widget. */
173 const char *value, /* Value of option. */
174 char *widgRec, /* Pointer to record for item. */
175 int offset) /* Offset into item. */
176 {
177 int c;
178 size_t length;
179
180 register int *orientPtr = (int *) (widgRec + offset);
181
182 if(value == NULL || *value == 0) {
183 *orientPtr = 0;
184 return TCL_OK;
185 }
186
187 c = value[0];
188 length = strlen(value);
189
190 if ((c == 'h') && (strncmp(value, "horizontal", length) == 0)) {
191 *orientPtr = 0;
192 return TCL_OK;
193 }
194 if ((c == 'v') && (strncmp(value, "vertical", length) == 0)) {
195 *orientPtr = 1;
196 return TCL_OK;
197 }
198 Tcl_AppendResult(interp, "bad orientation \"", value,
199 "\": must be vertical or horizontal", NULL);
200 *orientPtr = 0;
201 return TCL_ERROR;
202 }
203
204 /*
205 *--------------------------------------------------------------
206 *
207 * TkOrientPrintProc --
208 *
209 * This function is invoked by the Tk configuration code to produce a
210 * printable string for the "-orient" configuration option.
211 *
212 * Results:
213 * The return value is a string describing the orientation for the item
214 * referred to by "widgRec". In addition, *freeProcPtr is filled in with
215 * the address of a function to call to free the result string when it's
216 * no longer needed (or NULL to indicate that the string doesn't need to
217 * be freed).
218 *
219 * Side effects:
220 * None.
221 *
222 *--------------------------------------------------------------
223 */
224
225 char *
TkOrientPrintProc(ClientData clientData,Tk_Window tkwin,char * widgRec,int offset,Tcl_FreeProc ** freeProcPtr)226 TkOrientPrintProc(
227 ClientData clientData, /* Ignored. */
228 Tk_Window tkwin, /* Window containing canvas widget. */
229 char *widgRec, /* Pointer to record for item. */
230 int offset, /* Offset into item. */
231 Tcl_FreeProc **freeProcPtr) /* Pointer to variable to fill in with
232 * information about how to reclaim storage
233 * for return string. */
234 {
235 register int *statePtr = (int *) (widgRec + offset);
236
237 if (*statePtr) {
238 return "vertical";
239 } else {
240 return "horizontal";
241 }
242 }
243
244 /*
245 *----------------------------------------------------------------------
246 *
247 * TkOffsetParseProc --
248 *
249 * Converts the offset of a stipple or tile into the Tk_TSOffset
250 * structure.
251 *
252 *----------------------------------------------------------------------
253 */
254
255 int
TkOffsetParseProc(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,const char * value,char * widgRec,int offset)256 TkOffsetParseProc(
257 ClientData clientData, /* not used */
258 Tcl_Interp *interp, /* Interpreter to send results back to */
259 Tk_Window tkwin, /* Window on same display as tile */
260 const char *value, /* Name of image */
261 char *widgRec, /* Widget structure record */
262 int offset) /* Offset of tile in record */
263 {
264 Tk_TSOffset *offsetPtr = (Tk_TSOffset *) (widgRec + offset);
265 Tk_TSOffset tsoffset;
266 const char *q, *p;
267 int result;
268
269 if ((value == NULL) || (*value == 0)) {
270 tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_MIDDLE;
271 goto goodTSOffset;
272 }
273 tsoffset.flags = 0;
274 p = value;
275
276 switch(value[0]) {
277 case '#':
278 if (PTR2INT(clientData) & TK_OFFSET_RELATIVE) {
279 tsoffset.flags = TK_OFFSET_RELATIVE;
280 p++;
281 break;
282 }
283 goto badTSOffset;
284 case 'e':
285 switch(value[1]) {
286 case '\0':
287 tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_MIDDLE;
288 goto goodTSOffset;
289 case 'n':
290 if (value[2]!='d' || value[3]!='\0') {
291 goto badTSOffset;
292 }
293 tsoffset.flags = INT_MAX;
294 goto goodTSOffset;
295 }
296 case 'w':
297 if (value[1] != '\0') {goto badTSOffset;}
298 tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_MIDDLE;
299 goto goodTSOffset;
300 case 'n':
301 if ((value[1] != '\0') && (value[2] != '\0')) {
302 goto badTSOffset;
303 }
304 switch(value[1]) {
305 case '\0':
306 tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_TOP;
307 goto goodTSOffset;
308 case 'w':
309 tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_TOP;
310 goto goodTSOffset;
311 case 'e':
312 tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_TOP;
313 goto goodTSOffset;
314 }
315 goto badTSOffset;
316 case 's':
317 if ((value[1] != '\0') && (value[2] != '\0')) {
318 goto badTSOffset;
319 }
320 switch(value[1]) {
321 case '\0':
322 tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_BOTTOM;
323 goto goodTSOffset;
324 case 'w':
325 tsoffset.flags = TK_OFFSET_LEFT|TK_OFFSET_BOTTOM;
326 goto goodTSOffset;
327 case 'e':
328 tsoffset.flags = TK_OFFSET_RIGHT|TK_OFFSET_BOTTOM;
329 goto goodTSOffset;
330 }
331 goto badTSOffset;
332 case 'c':
333 if (strncmp(value, "center", strlen(value)) != 0) {
334 goto badTSOffset;
335 }
336 tsoffset.flags = TK_OFFSET_CENTER|TK_OFFSET_MIDDLE;
337 goto goodTSOffset;
338 }
339 if ((q = strchr(p,',')) == NULL) {
340 if (PTR2INT(clientData) & TK_OFFSET_INDEX) {
341 if (Tcl_GetInt(interp, (char *) p, &tsoffset.flags) != TCL_OK) {
342 Tcl_ResetResult(interp);
343 goto badTSOffset;
344 }
345 tsoffset.flags |= TK_OFFSET_INDEX;
346 goto goodTSOffset;
347 }
348 goto badTSOffset;
349 }
350 *((char *) q) = 0;
351 result = Tk_GetPixels(interp, tkwin, (char *) p, &tsoffset.xoffset);
352 *((char *) q) = ',';
353 if (result != TCL_OK) {
354 return TCL_ERROR;
355 }
356 if (Tk_GetPixels(interp, tkwin, (char*)q+1, &tsoffset.yoffset) != TCL_OK) {
357 return TCL_ERROR;
358 }
359
360 goodTSOffset:
361 /*
362 * Below is a hack to allow the stipple/tile offset to be stored in the
363 * internal tile structure. Most of the times, offsetPtr is a pointer to
364 * an already existing tile structure. However if this structure is not
365 * already created, we must do it with Tk_GetTile()!!!!;
366 */
367
368 memcpy(offsetPtr, &tsoffset, sizeof(Tk_TSOffset));
369 return TCL_OK;
370
371 badTSOffset:
372 Tcl_AppendResult(interp, "bad offset \"", value,
373 "\": expected \"x,y\"", NULL);
374 if (PTR2INT(clientData) & TK_OFFSET_RELATIVE) {
375 Tcl_AppendResult(interp, ", \"#x,y\"", NULL);
376 }
377 if (PTR2INT(clientData) & TK_OFFSET_INDEX) {
378 Tcl_AppendResult(interp, ", <index>", NULL);
379 }
380 Tcl_AppendResult(interp, ", n, ne, e, se, s, sw, w, nw, or center", NULL);
381 return TCL_ERROR;
382 }
383
384 /*
385 *----------------------------------------------------------------------
386 *
387 * TkOffsetPrintProc --
388 *
389 * Returns the offset of the tile.
390 *
391 * Results:
392 * The offset of the tile is returned.
393 *
394 *----------------------------------------------------------------------
395 */
396
397 char *
TkOffsetPrintProc(ClientData clientData,Tk_Window tkwin,char * widgRec,int offset,Tcl_FreeProc ** freeProcPtr)398 TkOffsetPrintProc(
399 ClientData clientData, /* not used */
400 Tk_Window tkwin, /* not used */
401 char *widgRec, /* Widget structure record */
402 int offset, /* Offset of tile in record */
403 Tcl_FreeProc **freeProcPtr) /* not used */
404 {
405 Tk_TSOffset *offsetPtr = (Tk_TSOffset *) (widgRec + offset);
406 char *p, *q;
407
408 if (offsetPtr->flags & TK_OFFSET_INDEX) {
409 if (offsetPtr->flags >= INT_MAX) {
410 return "end";
411 }
412 p = (char *) ckalloc(32);
413 sprintf(p, "%d", offsetPtr->flags & ~TK_OFFSET_INDEX);
414 *freeProcPtr = TCL_DYNAMIC;
415 return p;
416 }
417 if (offsetPtr->flags & TK_OFFSET_TOP) {
418 if (offsetPtr->flags & TK_OFFSET_LEFT) {
419 return "nw";
420 } else if (offsetPtr->flags & TK_OFFSET_CENTER) {
421 return "n";
422 } else if (offsetPtr->flags & TK_OFFSET_RIGHT) {
423 return "ne";
424 }
425 } else if (offsetPtr->flags & TK_OFFSET_MIDDLE) {
426 if (offsetPtr->flags & TK_OFFSET_LEFT) {
427 return "w";
428 } else if (offsetPtr->flags & TK_OFFSET_CENTER) {
429 return "center";
430 } else if (offsetPtr->flags & TK_OFFSET_RIGHT) {
431 return "e";
432 }
433 } else if (offsetPtr->flags & TK_OFFSET_BOTTOM) {
434 if (offsetPtr->flags & TK_OFFSET_LEFT) {
435 return "sw";
436 } else if (offsetPtr->flags & TK_OFFSET_CENTER) {
437 return "s";
438 } else if (offsetPtr->flags & TK_OFFSET_RIGHT) {
439 return "se";
440 }
441 }
442 q = p = (char *) ckalloc(32);
443 if (offsetPtr->flags & TK_OFFSET_RELATIVE) {
444 *q++ = '#';
445 }
446 sprintf(q, "%d,%d", offsetPtr->xoffset, offsetPtr->yoffset);
447 *freeProcPtr = TCL_DYNAMIC;
448 return p;
449 }
450
451 /*
452 *----------------------------------------------------------------------
453 *
454 * TkPixelParseProc --
455 *
456 * Converts the name of an image into a tile.
457 *
458 *----------------------------------------------------------------------
459 */
460
461 int
TkPixelParseProc(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,const char * value,char * widgRec,int offset)462 TkPixelParseProc(
463 ClientData clientData, /* If non-NULL, negative values are allowed as
464 * well */
465 Tcl_Interp *interp, /* Interpreter to send results back to */
466 Tk_Window tkwin, /* Window on same display as tile */
467 const char *value, /* Name of image */
468 char *widgRec, /* Widget structure record */
469 int offset) /* Offset of tile in record */
470 {
471 double *doublePtr = (double *) (widgRec + offset);
472 int result;
473
474 result = TkGetDoublePixels(interp, tkwin, value, doublePtr);
475
476 if ((result == TCL_OK) && (clientData == NULL) && (*doublePtr < 0.0)) {
477 Tcl_AppendResult(interp, "bad screen distance \"", value, "\"", NULL);
478 return TCL_ERROR;
479 }
480 return result;
481 }
482
483 /*
484 *----------------------------------------------------------------------
485 *
486 * TkPixelPrintProc --
487 *
488 * Returns the name of the tile.
489 *
490 * Results:
491 * The name of the tile is returned.
492 *
493 *----------------------------------------------------------------------
494 */
495
496 char *
TkPixelPrintProc(ClientData clientData,Tk_Window tkwin,char * widgRec,int offset,Tcl_FreeProc ** freeProcPtr)497 TkPixelPrintProc(
498 ClientData clientData, /* not used */
499 Tk_Window tkwin, /* not used */
500 char *widgRec, /* Widget structure record */
501 int offset, /* Offset of tile in record */
502 Tcl_FreeProc **freeProcPtr) /* not used */
503 {
504 double *doublePtr = (double *) (widgRec + offset);
505 char *p = (char *) ckalloc(24);
506
507 Tcl_PrintDouble(NULL, *doublePtr, p);
508 *freeProcPtr = TCL_DYNAMIC;
509 return p;
510 }
511
512 /*
513 *----------------------------------------------------------------------
514 *
515 * TkDrawInsetFocusHighlight --
516 *
517 * This function draws a rectangular ring around the outside of a widget
518 * to indicate that it has received the input focus. It takes an
519 * additional padding argument that specifies how much padding is present
520 * outside the widget.
521 *
522 * Results:
523 * None.
524 *
525 * Side effects:
526 * A rectangle "width" pixels wide is drawn in "drawable", corresponding
527 * to the outer area of "tkwin".
528 *
529 *----------------------------------------------------------------------
530 */
531
532 void
TkDrawInsetFocusHighlight(Tk_Window tkwin,GC gc,int width,Drawable drawable,int padding)533 TkDrawInsetFocusHighlight(
534 Tk_Window tkwin, /* Window whose focus highlight ring is to be
535 * drawn. */
536 GC gc, /* Graphics context to use for drawing the
537 * highlight ring. */
538 int width, /* Width of the highlight ring, in pixels. */
539 Drawable drawable, /* Where to draw the ring (typically a pixmap
540 * for double buffering). */
541 int padding) /* Width of padding outside of widget. */
542 {
543 XRectangle rects[4];
544
545 rects[0].x = padding;
546 rects[0].y = padding;
547 rects[0].width = Tk_Width(tkwin) - (2 * padding);
548 rects[0].height = width;
549 rects[1].x = padding;
550 rects[1].y = Tk_Height(tkwin) - width - padding;
551 rects[1].width = Tk_Width(tkwin) - (2 * padding);
552 rects[1].height = width;
553 rects[2].x = padding;
554 rects[2].y = width + padding;
555 rects[2].width = width;
556 rects[2].height = Tk_Height(tkwin) - 2*width - 2*padding;
557 rects[3].x = Tk_Width(tkwin) - width - padding;
558 rects[3].y = rects[2].y;
559 rects[3].width = width;
560 rects[3].height = rects[2].height;
561 XFillRectangles(Tk_Display(tkwin), drawable, gc, rects, 4);
562 }
563
564 /*
565 *----------------------------------------------------------------------
566 *
567 * Tk_DrawFocusHighlight --
568 *
569 * This function draws a rectangular ring around the outside of a widget
570 * to indicate that it has received the input focus.
571 *
572 * This function is now deprecated. Use TkpDrawHighlightBorder instead,
573 * since this function does not handle drawing the Focus ring properly on
574 * the Macintosh - you need to know the background GC as well as the
575 * foreground since the Mac focus ring separated from the widget by a 1
576 * pixel border.
577 *
578 * Results:
579 * None.
580 *
581 * Side effects:
582 * A rectangle "width" pixels wide is drawn in "drawable", corresponding
583 * to the outer area of "tkwin".
584 *
585 *----------------------------------------------------------------------
586 */
587
588 void
Tk_DrawFocusHighlight(Tk_Window tkwin,GC gc,int width,Drawable drawable)589 Tk_DrawFocusHighlight(
590 Tk_Window tkwin, /* Window whose focus highlight ring is to be
591 * drawn. */
592 GC gc, /* Graphics context to use for drawing the
593 * highlight ring. */
594 int width, /* Width of the highlight ring, in pixels. */
595 Drawable drawable) /* Where to draw the ring (typically a pixmap
596 * for double buffering). */
597 {
598 TkDrawInsetFocusHighlight(tkwin, gc, width, drawable, 0);
599 }
600
601 /*
602 *----------------------------------------------------------------------
603 *
604 * Tk_GetScrollInfo --
605 *
606 * This function is invoked to parse "xview" and "yview" scrolling
607 * commands for widgets using the new scrolling command syntax ("moveto"
608 * or "scroll" options).
609 *
610 * Results:
611 * The return value is either TK_SCROLL_MOVETO, TK_SCROLL_PAGES,
612 * TK_SCROLL_UNITS, or TK_SCROLL_ERROR. This indicates whether the
613 * command was successfully parsed and what form the command took. If
614 * TK_SCROLL_MOVETO, *dblPtr is filled in with the desired position; if
615 * TK_SCROLL_PAGES or TK_SCROLL_UNITS, *intPtr is filled in with the
616 * number of lines to move (may be negative); if TK_SCROLL_ERROR, the
617 * interp's result contains an error message.
618 *
619 * Side effects:
620 * None.
621 *
622 *----------------------------------------------------------------------
623 */
624
625 int
Tk_GetScrollInfo(Tcl_Interp * interp,int argc,const char ** argv,double * dblPtr,int * intPtr)626 Tk_GetScrollInfo(
627 Tcl_Interp *interp, /* Used for error reporting. */
628 int argc, /* # arguments for command. */
629 const char **argv, /* Arguments for command. */
630 double *dblPtr, /* Filled in with argument "moveto" option, if
631 * any. */
632 int *intPtr) /* Filled in with number of pages or lines to
633 * scroll, if any. */
634 {
635 int c = argv[2][0];
636 size_t length = strlen(argv[2]);
637
638 if ((c == 'm') && (strncmp(argv[2], "moveto", length) == 0)) {
639 if (argc != 4) {
640 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
641 " ", argv[1], " moveto fraction\"", NULL);
642 return TK_SCROLL_ERROR;
643 }
644 if (Tcl_GetDouble(interp, argv[3], dblPtr) != TCL_OK) {
645 return TK_SCROLL_ERROR;
646 }
647 return TK_SCROLL_MOVETO;
648 } else if ((c == 's')
649 && (strncmp(argv[2], "scroll", length) == 0)) {
650 if (argc != 5) {
651 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
652 " ", argv[1], " scroll number units|pages\"", NULL);
653 return TK_SCROLL_ERROR;
654 }
655 if (Tcl_GetInt(interp, argv[3], intPtr) != TCL_OK) {
656 return TK_SCROLL_ERROR;
657 }
658 length = strlen(argv[4]);
659 c = argv[4][0];
660 if ((c == 'p') && (strncmp(argv[4], "pages", length) == 0)) {
661 return TK_SCROLL_PAGES;
662 } else if ((c == 'u') && (strncmp(argv[4], "units", length) == 0)) {
663 return TK_SCROLL_UNITS;
664 }
665
666 Tcl_AppendResult(interp, "bad argument \"", argv[4],
667 "\": must be units or pages", NULL);
668 return TK_SCROLL_ERROR;
669 }
670 Tcl_AppendResult(interp, "unknown option \"", argv[2],
671 "\": must be moveto or scroll", NULL);
672 return TK_SCROLL_ERROR;
673 }
674
675 /*
676 *----------------------------------------------------------------------
677 *
678 * Tk_GetScrollInfoObj --
679 *
680 * This function is invoked to parse "xview" and "yview" scrolling
681 * commands for widgets using the new scrolling command syntax ("moveto"
682 * or "scroll" options).
683 *
684 * Results:
685 * The return value is either TK_SCROLL_MOVETO, TK_SCROLL_PAGES,
686 * TK_SCROLL_UNITS, or TK_SCROLL_ERROR. This indicates whether the
687 * command was successfully parsed and what form the command took. If
688 * TK_SCROLL_MOVETO, *dblPtr is filled in with the desired position; if
689 * TK_SCROLL_PAGES or TK_SCROLL_UNITS, *intPtr is filled in with the
690 * number of lines to move (may be negative); if TK_SCROLL_ERROR, the
691 * interp's result contains an error message.
692 *
693 * Side effects:
694 * None.
695 *
696 *----------------------------------------------------------------------
697 */
698
699 int
Tk_GetScrollInfoObj(Tcl_Interp * interp,int objc,Tcl_Obj * const objv[],double * dblPtr,int * intPtr)700 Tk_GetScrollInfoObj(
701 Tcl_Interp *interp, /* Used for error reporting. */
702 int objc, /* # arguments for command. */
703 Tcl_Obj *const objv[], /* Arguments for command. */
704 double *dblPtr, /* Filled in with argument "moveto" option, if
705 * any. */
706 int *intPtr) /* Filled in with number of pages or lines to
707 * scroll, if any. */
708 {
709 int length;
710 const char *arg;
711
712 arg = Tcl_GetStringFromObj(objv[2], &length);
713
714 #define ArgPfxEq(str) ((arg[0]==str[0])&&!strncmp(arg,str,(unsigned)length))
715
716 if (ArgPfxEq("moveto")) {
717 if (objc != 4) {
718 Tcl_WrongNumArgs(interp, 2, objv, "moveto fraction");
719 return TK_SCROLL_ERROR;
720 }
721 if (Tcl_GetDoubleFromObj(interp, objv[3], dblPtr) != TCL_OK) {
722 return TK_SCROLL_ERROR;
723 }
724 return TK_SCROLL_MOVETO;
725 } else if (ArgPfxEq("scroll")) {
726 if (objc != 5) {
727 Tcl_WrongNumArgs(interp, 2, objv, "scroll number units|pages");
728 return TK_SCROLL_ERROR;
729 }
730 if (Tcl_GetIntFromObj(interp, objv[3], intPtr) != TCL_OK) {
731 return TK_SCROLL_ERROR;
732 }
733
734 arg = Tcl_GetStringFromObj(objv[4], &length);
735 if (ArgPfxEq("pages")) {
736 return TK_SCROLL_PAGES;
737 } else if (ArgPfxEq("units")) {
738 return TK_SCROLL_UNITS;
739 }
740
741 Tcl_AppendResult(interp, "bad argument \"", arg,
742 "\": must be units or pages", NULL);
743 return TK_SCROLL_ERROR;
744 }
745 Tcl_AppendResult(interp, "unknown option \"", arg,
746 "\": must be moveto or scroll", NULL);
747 return TK_SCROLL_ERROR;
748 }
749
750 /*
751 *---------------------------------------------------------------------------
752 *
753 * TkComputeAnchor --
754 *
755 * Determine where to place a rectangle so that it will be properly
756 * anchored with respect to the given window. Used by widgets to align a
757 * box of text inside a window. When anchoring with respect to one of the
758 * sides, the rectangle be placed inside of the internal border of the
759 * window.
760 *
761 * Results:
762 * *xPtr and *yPtr set to the upper-left corner of the rectangle anchored
763 * in the window.
764 *
765 * Side effects:
766 * None.
767 *
768 *---------------------------------------------------------------------------
769 */
770
771 void
TkComputeAnchor(Tk_Anchor anchor,Tk_Window tkwin,int padX,int padY,int innerWidth,int innerHeight,int * xPtr,int * yPtr)772 TkComputeAnchor(
773 Tk_Anchor anchor, /* Desired anchor. */
774 Tk_Window tkwin, /* Anchored with respect to this window. */
775 int padX, int padY, /* Use this extra padding inside window, in
776 * addition to the internal border. */
777 int innerWidth, int innerHeight,
778 /* Size of rectangle to anchor in window. */
779 int *xPtr, int *yPtr) /* Returns upper-left corner of anchored
780 * rectangle. */
781 {
782 /*
783 * Handle the horizontal parts.
784 */
785
786 switch (anchor) {
787 case TK_ANCHOR_NW:
788 case TK_ANCHOR_W:
789 case TK_ANCHOR_SW:
790 *xPtr = Tk_InternalBorderLeft(tkwin) + padX;
791 break;
792
793 case TK_ANCHOR_N:
794 case TK_ANCHOR_CENTER:
795 case TK_ANCHOR_S:
796 *xPtr = (Tk_Width(tkwin) - innerWidth - Tk_InternalBorderLeft(tkwin) -
797 Tk_InternalBorderRight(tkwin)) / 2 +
798 Tk_InternalBorderLeft(tkwin);
799 break;
800
801 default:
802 *xPtr = Tk_Width(tkwin) - Tk_InternalBorderRight(tkwin) - padX
803 - innerWidth;
804 break;
805 }
806
807 /*
808 * Handle the vertical parts.
809 */
810
811 switch (anchor) {
812 case TK_ANCHOR_NW:
813 case TK_ANCHOR_N:
814 case TK_ANCHOR_NE:
815 *yPtr = Tk_InternalBorderTop(tkwin) + padY;
816 break;
817
818 case TK_ANCHOR_W:
819 case TK_ANCHOR_CENTER:
820 case TK_ANCHOR_E:
821 *yPtr = (Tk_Height(tkwin) - innerHeight- Tk_InternalBorderTop(tkwin) -
822 Tk_InternalBorderBottom(tkwin)) / 2 +
823 Tk_InternalBorderTop(tkwin);
824 break;
825
826 default:
827 *yPtr = Tk_Height(tkwin) - Tk_InternalBorderBottom(tkwin) - padY
828 - innerHeight;
829 break;
830 }
831 }
832
833 /*
834 *---------------------------------------------------------------------------
835 *
836 * TkFindStateString --
837 *
838 * Given a lookup table, map a number to a string in the table.
839 *
840 * Results:
841 * If numKey was equal to the numeric key of one of the elements in the
842 * table, returns the string key of that element. Returns NULL if numKey
843 * was not equal to any of the numeric keys in the table.
844 *
845 * Side effects.
846 * None.
847 *
848 *---------------------------------------------------------------------------
849 */
850
851 char *
TkFindStateString(const TkStateMap * mapPtr,int numKey)852 TkFindStateString(
853 const TkStateMap *mapPtr, /* The state table. */
854 int numKey) /* The key to try to find in the table. */
855 {
856 for (; mapPtr->strKey!=NULL ; mapPtr++) {
857 if (numKey == mapPtr->numKey) {
858 return (char *) mapPtr->strKey;
859 }
860 }
861 return NULL;
862 }
863
864 /*
865 *---------------------------------------------------------------------------
866 *
867 * TkFindStateNum, TkFindStateNumObj --
868 *
869 * Given a lookup table, map a string to a number in the table.
870 *
871 * Results:
872 * If strKey was equal to the string keys of one of the elements in the
873 * table, returns the numeric key of that element. Returns the numKey
874 * associated with the last element (the NULL string one) in the table if
875 * strKey was not equal to any of the string keys in the table. In that
876 * case, an error message is also left in the interp's result (if interp
877 * is not NULL).
878 *
879 * Side effects.
880 * None.
881 *
882 *---------------------------------------------------------------------------
883 */
884
885 int
TkFindStateNum(Tcl_Interp * interp,const char * option,const TkStateMap * mapPtr,const char * strKey)886 TkFindStateNum(
887 Tcl_Interp *interp, /* Interp for error reporting. */
888 const char *option, /* String to use when constructing error. */
889 const TkStateMap *mapPtr, /* Lookup table. */
890 const char *strKey) /* String to try to find in lookup table. */
891 {
892 const TkStateMap *mPtr;
893
894 /*
895 * See if the value is in the state map.
896 */
897
898 for (mPtr = mapPtr; mPtr->strKey != NULL; mPtr++) {
899 if (strcmp(strKey, mPtr->strKey) == 0) {
900 return mPtr->numKey;
901 }
902 }
903
904 /*
905 * Not there. Generate an error message (if we can) and return the
906 * default.
907 */
908
909 if (interp != NULL) {
910 mPtr = mapPtr;
911 Tcl_AppendResult(interp, "bad ", option, " value \"", strKey,
912 "\": must be ", mPtr->strKey, NULL);
913 for (mPtr++; mPtr->strKey != NULL; mPtr++) {
914 Tcl_AppendResult(interp,
915 ((mPtr[1].strKey != NULL) ? ", " : ", or "),
916 mPtr->strKey, NULL);
917 }
918 }
919 return mPtr->numKey;
920 }
921
922 int
TkFindStateNumObj(Tcl_Interp * interp,Tcl_Obj * optionPtr,const TkStateMap * mapPtr,Tcl_Obj * keyPtr)923 TkFindStateNumObj(
924 Tcl_Interp *interp, /* Interp for error reporting. */
925 Tcl_Obj *optionPtr, /* String to use when constructing error. */
926 const TkStateMap *mapPtr, /* Lookup table. */
927 Tcl_Obj *keyPtr) /* String key to find in lookup table. */
928 {
929 const TkStateMap *mPtr;
930 const char *key;
931 const Tcl_ObjType *typePtr;
932
933 /*
934 * See if the value is in the object cache.
935 */
936
937 if ((keyPtr->typePtr == &tkStateKeyObjType)
938 && (keyPtr->internalRep.twoPtrValue.ptr1 == mapPtr)) {
939 return PTR2INT(keyPtr->internalRep.twoPtrValue.ptr2);
940 }
941
942 /*
943 * Not there. Look in the state map.
944 */
945
946 key = Tcl_GetStringFromObj(keyPtr, NULL);
947 for (mPtr = mapPtr; mPtr->strKey != NULL; mPtr++) {
948 if (strcmp(key, mPtr->strKey) == 0) {
949 typePtr = keyPtr->typePtr;
950 if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
951 (*typePtr->freeIntRepProc)(keyPtr);
952 }
953 keyPtr->internalRep.twoPtrValue.ptr1 = (void *) mapPtr;
954 keyPtr->internalRep.twoPtrValue.ptr2 = INT2PTR(mPtr->numKey);
955 keyPtr->typePtr = &tkStateKeyObjType;
956 return mPtr->numKey;
957 }
958 }
959
960 /*
961 * Not there either. Generate an error message (if we can) and return the
962 * default.
963 */
964
965 if (interp != NULL) {
966 mPtr = mapPtr;
967 Tcl_AppendResult(interp, "bad ", Tcl_GetString(optionPtr),
968 " value \"", key, "\": must be ", mPtr->strKey, NULL);
969 for (mPtr++; mPtr->strKey != NULL; mPtr++) {
970 Tcl_AppendResult(interp,
971 ((mPtr[1].strKey != NULL) ? ", " : ", or "),
972 mPtr->strKey, NULL);
973 }
974 }
975 return mPtr->numKey;
976 }
977
978 /*
979 * Local Variables:
980 * mode: c
981 * c-basic-offset: 4
982 * fill-column: 78
983 * End:
984 */
985