1 /*************************************<+>*************************************
2 *****************************************************************************
3 **
4 ** File: SText.c
5 **
6 ** Project: X Widgets
7 **
8 ** Description: Code/Definitions for StaticText widget class.
9 **
10 *****************************************************************************
11 **
12 ** Copyright (c) 1988 by Hewlett-Packard Company
13 ** Copyright (c) 1988 by the Massachusetts Institute of Technology
14 **
15 ** Permission to use, copy, modify, and distribute this software
16 ** and its documentation for any purpose and without fee is hereby
17 ** granted, provided that the above copyright notice appear in all
18 ** copies and that both that copyright notice and this permission
19 ** notice appear in supporting documentation, and that the names of
20 ** Hewlett-Packard or M.I.T. not be used in advertising or publicity
21 ** pertaining to distribution of the software without specific, written
22 ** prior permission.
23 **
24 *****************************************************************************
25 *************************************<+>*************************************/
26
27 /*
28 * Include files & Static Routine Definitions
29 */
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <X11/StringDefs.h>
35 #include <X11/IntrinsicP.h>
36 #include <X11/Intrinsic.h>
37 #include <X11/keysymdef.h>
38 #include <Xw/Xw.h>
39 #include <Xw/XwP.h>
40 #include <Xw/SText.h>
41 #include <Xw/STextP.h>
42
43 static void Initialize ();
44 static void Realize();
45 static void Destroy();
46 static void Resize();
47 static Boolean SetValues();
48 static void Redisplay();
49 static void Select();
50 static void Release();
51 static void Toggle();
52 static void ClassInitialize();
53
54
55 /*************************************<->*************************************
56 *
57 *
58 * Description: default translation table for class: StaticText
59 * -----------
60 *
61 * Matches events with string descriptors for internal routines.
62 *
63 *************************************<->***********************************/
64
65 static char defaultTranslations[] =
66 "<EnterWindow>: enter()\n\
67 <LeaveWindow>: leave()\n\
68 <Btn1Down>: select()\n\
69 <Btn1Up>: release()\n\
70 <KeyDown>Select: select() \n\
71 <KeyUp>Select: release()";
72
73
74 /*************************************<->*************************************
75 *
76 *
77 * Description: action list for class: StaticText
78 * -----------
79 *
80 * Matches string descriptors with internal routines.
81 * Note that Primitive will register additional event handlers
82 * for traversal.
83 *
84 *************************************<->***********************************/
85
86 static XtActionsRec actionsList[] =
87 {
88 { "enter", (XtActionProc) _XwPrimitiveEnter },
89 { "leave", (XtActionProc) _XwPrimitiveLeave },
90 { "select", (XtActionProc) Select },
91 { "release", (XtActionProc) Release },
92 {"toggle", (XtActionProc) Toggle },
93 };
94
95
96 /*************************************<->*************************************
97 *
98 *
99 * Description: resource list for class: StaticText
100 * -----------
101 *
102 * Provides default resource settings for instances of this class.
103 * To get full set of default settings, examine resouce list of super
104 * classes of this class.
105 *
106 *************************************<->***********************************/
107
108 static XtResource resources[] = {
109 { XtNhSpace,
110 XtCHSpace,
111 XtRDimension,
112 sizeof(Dimension),
113 XtOffset(XwStaticTextWidget, static_text.internal_width),
114 XtRString,
115 "2"
116 },
117 { XtNvSpace,
118 XtCVSpace,
119 XtRDimension,
120 sizeof(Dimension),
121 XtOffset(XwStaticTextWidget, static_text.internal_height),
122 XtRString,
123 "2"
124 },
125 { XtNalignment,
126 XtCAlignment,
127 XtRAlignment,
128 sizeof(XwAlignment),
129 XtOffset(XwStaticTextWidget,static_text.alignment),
130 XtRString,
131 "Left"
132 },
133 { XtNgravity,
134 XtCGravity,
135 XtRGravity,
136 sizeof(int),
137 XtOffset(XwStaticTextWidget,static_text.gravity),
138 XtRString,
139 "CenterGravity"
140 },
141 { XtNwrap,
142 XtCWrap,
143 XtRBoolean,
144 sizeof(Boolean),
145 XtOffset(XwStaticTextWidget,static_text.wrap),
146 XtRString,
147 "TRUE"
148 },
149 { XtNstrip,
150 XtCStrip,
151 XtRBoolean,
152 sizeof(Boolean),
153 XtOffset(XwStaticTextWidget,static_text.strip),
154 XtRString,
155 "TRUE"
156 },
157 { XtNlineSpace,
158 XtCLineSpace,
159 XtRInt,
160 sizeof(int),
161 XtOffset(XwStaticTextWidget,static_text.line_space),
162 XtRString,
163 "0"
164 },
165 { XtNfont,
166 XtCFont,
167 XtRFontStruct,
168 sizeof(XFontStruct *),
169 XtOffset(XwStaticTextWidget,static_text.font),
170 XtRString,
171 "Fixed"
172 },
173 { XtNstring,
174 XtCString,
175 XtRString,
176 sizeof(char *),
177 XtOffset(XwStaticTextWidget, static_text.input_string),
178 XtRString,
179 NULL
180 },
181 };
182
183
184
185 /*************************************<->*************************************
186 *
187 *
188 * Description: global class record for instances of class: StaticText
189 * -----------
190 *
191 * Defines default field settings for this class record.
192 *
193 *************************************<->***********************************/
194
195 XwStaticTextClassRec XwstatictextClassRec = {
196 { /* core_class fields */
197 /* superclass */ (WidgetClass) &XwprimitiveClassRec,
198 /* class_name */ "XwStaticText",
199 /* widget_size */ sizeof(XwStaticTextRec),
200 /* class_initialize */ ClassInitialize,
201 /* class_part_initialize */ NULL,
202 /* class_inited */ FALSE,
203 /* initialize */ (XtInitProc) Initialize,
204 /* initialize_hook */ NULL,
205 /* realize */ (XtRealizeProc) Realize,
206 /* actions */ actionsList,
207 /* num_actions */ XtNumber(actionsList),
208 /* resources */ resources,
209 /* num_resources */ XtNumber(resources),
210 /* xrm_class */ NULLQUARK,
211 /* compress_motion */ TRUE,
212 /* compress_exposure */ TRUE,
213 /* compress_enterleave */ TRUE,
214 /* visible_interest */ FALSE,
215 /* destroy */ (XtWidgetProc) Destroy,
216 /* resize */ (XtWidgetProc) Resize,
217 /* expose */ (XtExposeProc) Redisplay,
218 /* set_values */ (XtSetValuesFunc) SetValues,
219 /* set_values_hook */ NULL,
220 /* set_values_almost */ (XtAlmostProc) XtInheritSetValuesAlmost,
221 /* get_values_hook */ NULL,
222 /* accept_focus */ NULL,
223 /* version */ XtVersion,
224 /* callback private */ NULL,
225 /* tm_table */ defaultTranslations,
226 /* query_geometry */ NULL,
227 /* display_accelerator */ XtInheritDisplayAccelerator,
228 /* extension */ NULL
229 },
230 {
231 NULL,
232 NULL,
233 NULL,
234 NULL,
235 NULL,
236 }
237 };
238
239 WidgetClass XwstatictextWidgetClass = (WidgetClass) &XwstatictextClassRec;
240 WidgetClass XwstaticTextWidgetClass = (WidgetClass) &XwstatictextClassRec;
241
242
243
244 /*************************************<->*************************************
245 *
246 * ClassInitialize
247 *
248 * Description:
249 * -----------
250 * Set fields in primitive class part of our class record so that
251 * the traversal code can invoke our select/release procedures (note
252 * that for this class toggle is a empty proc).
253 *
254 *************************************<->***********************************/
ClassInitialize()255 static void ClassInitialize()
256 {
257 XwstatictextClassRec.primitive_class.select_proc = (XwEventProc) Select;
258 XwstatictextClassRec.primitive_class.release_proc = (XwEventProc) Release;
259 XwstatictextClassRec.primitive_class.toggle_proc = (XwEventProc) Toggle;
260 }
261
262
263 /*************************************<->*************************************
264 *
265 * Procedures and variables private to StaticText
266 *
267 *************************************<->************************************/
268
269 static void ValidateInputs();
270 static void SetNormalGC();
271 static int RetCount();
272 static int Maxline();
273 static void FormatText();
274 static void GetTextRect();
275 static void SetSize();
276
277
278 /*************************************<->*************************************
279 *
280 * static void ValidateInputs(stw)
281 * XwStaticTextWidget stw;
282 *
283 * Description:
284 * -----------
285 * Checks a StaticText widget for nonsensical values, and changes
286 * nonsense values into meaninful values.
287 *
288 * Inputs:
289 * ------
290 *
291 * Outputs:
292 * -------
293 *
294 * Procedures Called
295 * -----------------
296 * XtWarning
297 *
298 *************************************<->***********************************/
ValidateInputs(stw)299 static void ValidateInputs(stw)
300 XwStaticTextWidget stw;
301 {
302 XwStaticTextPart *stp;
303
304 stp = &(stw->static_text);
305
306 /*
307 *Check line_spacing. We will allow text to over write,
308 * we will not allow it to move from bottom to top.
309 */
310 if (stp->line_space < -100)
311 {
312 XtWarning("XwStaticTextWidget: line_space was less than -100, set to 0\n");
313 stp->line_space = 0;
314 }
315
316 /*
317 * Check Alignment
318 */
319
320 switch(stp->alignment)
321 {
322 case XwALIGN_LEFT:
323 case XwALIGN_CENTER:
324 case XwALIGN_RIGHT:
325 /* Valid values. */
326 break;
327 default:
328 XtWarning("XwStaticTextWidget: Unknown alignment, set to Left instead");
329 stp->alignment = XwALIGN_LEFT;
330 break;
331 }
332
333 }
334
335
336 /*************************************<->*************************************
337 *
338 * static void SetNormalGC (stw)
339 * XwStaticTextWidget stw;
340 *
341 * Description:
342 * -----------
343 * Sets up a GC for the static text widget to write to.
344 *
345 * Inputs:
346 * ------
347 * stw = Points to an instance structure which has primitive.foreground
348 * core.background_pixel and static_text.font appropriately
349 * filled in with values.
350 *
351 * Outputs:
352 * -------
353 * Associates static_text.normal_GC with a GC.
354 *
355 * Procedures Called
356 * -----------------
357 * XCreateGC
358 * XSetClipRectangles
359 *
360 *************************************<->***********************************/
SetNormalGC(stw)361 static void SetNormalGC(stw)
362 XwStaticTextWidget stw;
363 {
364 XGCValues values;
365 XtGCMask valueMask;
366 XRectangle ClipRect;
367
368 valueMask = GCForeground | GCBackground | GCFont;
369
370 values.foreground = stw->primitive.foreground;
371 values.background = stw->core.background_pixel;
372 values.font = stw->static_text.font->fid;
373
374 stw->static_text.normal_GC = XCreateGC(XtDisplay(stw),XtWindow(stw),
375 valueMask,&values);
376 /*
377 * Set the Clip Region.
378 */
379 ClipRect.width = stw->core.width -
380 (2 * (stw->static_text.internal_width +
381 stw->primitive.highlight_thickness));
382 ClipRect.height = stw->core.height -
383 (2 * (stw->static_text.internal_height +
384 stw->primitive.highlight_thickness));
385 ClipRect.x = stw->primitive.highlight_thickness +
386 stw->static_text.internal_width;
387 ClipRect.y = stw->primitive.highlight_thickness +
388 stw->static_text.internal_height;
389
390 XSetClipRectangles(XtDisplay(stw),stw->static_text.normal_GC,
391 0,0, &ClipRect,1,Unsorted);
392 }
393
394
395 /*************************************<->*************************************
396 *
397 * static int RetCount(string)
398 * char *string;
399 *
400 * Description:
401 * -----------
402 * This routine returns the number of '\n' characters in "string"
403 *
404 * Inputs:
405 * ------
406 * string = The string to be counted.
407 *
408 * Outputs:
409 * -------
410 * The number of '\n' characters in the string.
411 *
412 * Procedures Called
413 * -----------------
414 *
415 *************************************<->***********************************/
RetCount(string)416 static int RetCount(string)
417 char *string;
418 {
419 int numlines;
420
421 numlines = (*string ? 1 : 0);
422 while (*string)
423 {
424 if (*string == '\n')
425 numlines++;
426 string++;
427 }
428 return(numlines);
429 }
430
431
432 /*************************************<->*************************************
433 *
434 * static int Maxline(string, font)
435 * char *string;
436 * XFontStruct *font;
437 *
438 * Description:
439 * -----------
440 * For a given string and a given font, returns the length of
441 * '\n' delimited series of characters.
442 *
443 * Inputs:
444 * ------
445 * string = The string to be analyzed.
446 * font = The font in which string is to be analyzed.
447 *
448 * Outputs:
449 * -------
450 * The maximun length in pixels of the longest '\n' delimited series of
451 * characters.
452 *
453 * Procedures Called
454 * -----------------
455 * XTextWidth
456 *
457 *************************************<->***********************************/
Maxline(stw)458 static int Maxline(stw)
459 XwStaticTextWidget stw;
460 {
461 int i, cur;
462 int max = 0;
463 char *str1, *str2, *str3;
464 XwAlignment alignment = stw->static_text.alignment;
465 XFontStruct *font = stw->static_text.font;
466 XwStaticTextPart *stp;
467
468 stp = &(stw->static_text);
469 str1 = stp->output_string;
470 while(*str1)
471 {
472 if ((stp->strip) &&
473 ((alignment == XwALIGN_LEFT) ||
474 (alignment == XwALIGN_CENTER)))
475 while (*str1 == ' ')
476 str1++;
477 str2 = str1;
478 for(i=0; ((*str1 != '\n') && *str1); i++, str1++);
479 if ((stp->strip) &&
480 ((alignment == XwALIGN_RIGHT) ||
481 (alignment == XwALIGN_CENTER)))
482 {
483 str3 = str1;
484 str3--;
485 while (*str3 == ' ')
486 i--, str3--;
487 }
488 if (i)
489 cur = XTextWidth(font,str2,i);
490 else
491 cur = 0;
492 if (cur > max)
493 max = cur;
494 if (*str1)
495 str1++; /* Step past the \n */
496 }
497 return(max);
498 }
499
500
501 /*************************************<->*************************************
502 *
503 * static void FormatText(stw)
504 * XwStaticTextWidget stw;
505 *
506 * Description:
507 * -----------
508 * Inserts newlines where necessary to fit stw->static_text.output_string
509 * into stw->core.width (if specified).
510 *
511 * Inputs:
512 * ------
513 * stw = The StaticText widget to be formatted.
514 *
515 * Outputs:
516 * -------
517 *
518 * Procedures Called
519 * -----------------
520 * XTextWidth
521 *
522 *************************************<->***********************************/
FormatText(stw)523 static void FormatText(stw)
524 XwStaticTextWidget stw;
525 {
526 int i, width, win, wordindex;
527 char *str1, *str2;
528 Boolean gotone;
529 XwStaticTextPart *stp;
530
531 stp = &(stw->static_text);
532 str1 = stp->output_string;
533
534 /* The available text window width is... */
535 win = stw->core.width - (2 * stp->internal_width)
536 - (2 * stw->primitive.highlight_thickness);
537
538 while (*str1)
539 {
540 i = 0;
541 width = 0;
542 wordindex = -1;
543 gotone = FALSE;
544 str2 = str1;
545 while (!gotone)
546 {
547 if ((stp->strip) && (wordindex == -1))
548 while (*str1 == ' ')
549 str1++;
550 /*
551 *Step through until a character that we can
552 * break on.
553 */
554 while ((*str1 != ' ') && (*str1 != '\n') && (*str1))
555 i++, str1++;
556
557 wordindex++;
558 width = (i ? XTextWidth(stp->font,str2,i) : 0);
559 width;
560 if (width < win)
561 {
562 /*
563 * If the current string fragment is shorter than the
564 * available window. Check to see if we are at a
565 * forced break or not, and process accordingly.
566 */
567 switch (*str1)
568 {
569 case ' ':
570 /*
571 * Add the space to the char count
572 */
573 i++;
574 /*
575 * Check to see there's room to start another
576 * word.
577 */
578 width = XTextWidth(stw->static_text.font,
579 str2,i);
580 if (width >= win)
581 {
582 /*
583 * Break the line if we can't start
584 * another word.
585 */
586 *str1 = '\n';
587 gotone = TRUE;
588 }
589 /*
590 * Step past the space
591 */
592 str1++;
593 break;
594 case '\n':
595 /*
596 * Forced break. Step pase the \n.
597 * Note the fall through to default.
598 */
599 str1++;
600 default:
601 /*
602 * End of string.
603 */
604 gotone = TRUE;
605 break;
606 }
607 }
608 else if (width > win)
609 {
610 /*
611 * We know that we have something
612 */
613 gotone = TRUE;
614
615 /*
616 * See if there is at least one space to back up for.
617 */
618 if (wordindex)
619 {
620 str1--;
621 while (*str1 != ' ')
622 str1--;
623 *str1++ = '\n';
624 }
625 else
626 /*
627 * We have a single word which is too long
628 * for the available window. Let the text
629 * clip rectangle handle it.
630 */
631 if (*str1)
632 *str1++ = '\n';
633 }
634 else /* (width == win) */
635 {
636 switch (*str1)
637 {
638 case ' ':
639 /*
640 * If we stopped on a space, change it.
641 */
642 *str1 = '\n';
643 case '\n':
644 /*
645 * Step past the \n.
646 */
647 str1++;
648 default:
649 gotone = TRUE;
650 break;
651 }
652 }
653 }
654 }
655 }
656
657
658 /*************************************<->*************************************
659 *
660 * static void GetTextRect(newstw)
661 * XwStaticTextWidget newstw;
662 *
663 * Description:
664 * -----------
665 * Sets newstw->static_text.TextRect to appropriate values given
666 * newstw->core.width and newstw->static_text.input_string. The
667 * string is formatted if necessary.
668 *
669 * A newstw->core.width value of 0 tells this procedure to choose
670 * its own size based soley on newstw->static_text.input_string.
671 *
672 * Inputs:
673 * ------
674 *
675 * Outputs:
676 * -------
677 *
678 * Procedures Called
679 * -----------------
680 * Maxline
681 * RetCount
682 *
683 *************************************<->***********************************/
GetTextRect(newstw)684 static void GetTextRect(newstw)
685 XwStaticTextWidget newstw;
686 {
687 int maxlen, maxwin, fheight, numrets;
688 XwStaticTextPart *stp;
689
690 stp = &(newstw->static_text);
691 /*
692 * Set the line height from the font structure.
693 */
694 fheight = stp->font->ascent + stp->font->descent;
695 if (newstw->core.width)
696 {
697 /*
698 * We were requested with a specific width. We must
699 * fit ourselves to it.
700 *
701 * The maximum available window width is...
702 */
703 maxwin = newstw->core.width - (2 * stp->internal_width)
704 - (2 * newstw->primitive.highlight_thickness);
705 if (stp->wrap)
706 {
707 if ((maxlen = Maxline(newstw)) <=
708 maxwin)
709 /*
710 * We fit without formatting.
711 */
712 stp->TextRect.width = maxlen;
713 else
714 {
715 stp->TextRect.width = maxwin;
716 /*
717 * Make the string fit.
718 */
719 FormatText(newstw);
720 }
721 }
722 else
723 stp->TextRect.width = Maxline(newstw);
724 }
725 else
726 stp->TextRect.width = Maxline(newstw);
727 /*
728 * See how tall the string wants to be.
729 */
730 numrets = RetCount(stp->output_string);
731 stp->TextRect.height = (fheight * numrets)
732 + (((numrets - 1) * (stp->line_space / 100.0)) * fheight);
733
734 if ((newstw->core.height) &&
735 ((newstw->core.height - (2 * stp->internal_height)
736 - (2 * newstw->primitive.highlight_thickness)) <
737 stp->TextRect.height))
738 /*
739 * Shorten the TextRect if the string wants
740 * to be too tall.
741 */
742 stp->TextRect.height = newstw->core.height
743 - (2 * stp->internal_height)
744 - (2 * newstw->primitive.highlight_thickness);
745 }
746
747
748 /*************************************<->*************************************
749 *
750 * static void SetSize(newstw)
751 * XwStaticTextWidget newstw;
752 *
753 * Description:
754 * -----------
755 * Copies newstw->static_text.input_string into output_string
756 *
757 * Sets newstw->core.width, newstw->core.height, and
758 * newstw->static_text.TextRect appropriately, formatting the
759 * string if necessary.
760 *
761 * The Clip Rectangle is placed in the window.
762 *
763 * Inputs:
764 * ------
765 * stw = A meaningful StaticTextWidget.
766 *
767 * Outputs:
768 * -------
769 *
770 * Procedures Called
771 * -----------------
772 * strcpy
773 * GetTextRect
774 *
775 *************************************<->***********************************/
SetSize(newstw)776 static void SetSize(newstw)
777 XwStaticTextWidget newstw;
778 {
779 XwStaticTextPart *stp;
780
781 stp = &(newstw->static_text);
782 /*
783 * Copy the input string into the output string.
784 */
785 if (stp->output_string != NULL)
786 XtFree(stp->output_string);
787 stp->output_string = XtMalloc(XwStrlen(stp->input_string)+1);
788 if(stp->input_string)
789 strcpy(stp->output_string,stp->input_string);
790 if (*(stp->output_string))
791 /*
792 * If we have a string then size it.
793 */
794 GetTextRect(newstw);
795 else
796 {
797 stp->TextRect.width = 0;
798 stp->TextRect.height = 0;
799 }
800 /*
801 * Has a size been specified?
802 */
803 if (newstw->core.width)
804 {
805 if ((newstw->core.width
806 - (2 * newstw->primitive.highlight_thickness)
807 - (2 * stp->internal_width)) > stp->TextRect.width)
808 {
809 /*
810 * Use the extra space according to the gravity
811 * resource setting.
812 */
813 switch (stp->gravity)
814 {
815 case EastGravity:
816 case NorthEastGravity:
817 case SouthEastGravity:
818 stp->TextRect.x = newstw->core.width -
819 (newstw->primitive.highlight_thickness +
820 stp->TextRect.width + stp->internal_width);
821 break;
822 case WestGravity:
823 case NorthWestGravity:
824 case SouthWestGravity:
825 stp->TextRect.x = stp->internal_width +
826 newstw->primitive.highlight_thickness;
827 break;
828 default:
829 stp->TextRect.x = (newstw->core.width
830 - stp->TextRect.width) / 2;
831 break;
832 }
833 }
834 else
835 /*
836 * We go to the left.
837 */
838 stp->TextRect.x = newstw->primitive.highlight_thickness
839 + stp->internal_width;
840 }
841 else
842 {
843 /*
844 * We go to the left.
845 */
846 stp->TextRect.x = newstw->primitive.highlight_thickness
847 + stp->internal_width;
848 newstw->core.width = stp->TextRect.width
849 + (2 * stp->internal_width)
850 + (2 * newstw->primitive.highlight_thickness);
851 }
852 /*
853 * Has a height been specified?
854 */
855 if (newstw->core.height)
856 {
857 if ((newstw->core.height - (2 * stp->internal_height)
858 - (2 * newstw->primitive.highlight_thickness)) >
859 stp->TextRect.height)
860 {
861 /*
862 * Use the extra space according to the gravity
863 * resource setting.
864 */
865 switch (stp->gravity)
866 {
867 case NorthGravity:
868 case NorthEastGravity:
869 case NorthWestGravity:
870 stp->TextRect.y = stp->internal_height +
871 newstw->primitive.highlight_thickness;
872 break;
873 case SouthGravity:
874 case SouthEastGravity:
875 case SouthWestGravity:
876 stp->TextRect.y = newstw->core.height -
877 (newstw->primitive.highlight_thickness +
878 stp->TextRect.height + stp->internal_width);
879 break;
880 default:
881 stp->TextRect.y = (newstw->core.height
882 - stp->TextRect.height)/ 2;
883 break;
884 }
885 }
886 else
887 {
888 /*
889 * We go to the top.
890 */
891 stp->TextRect.y = newstw->primitive.highlight_thickness
892 + stp->internal_height;
893 }
894 }
895 else
896 {
897 /*
898 * We go to the top.
899 */
900 stp->TextRect.y = newstw->primitive.highlight_thickness
901 + stp->internal_height;
902 /*
903 * We add our size to the current size.
904 * (Primitive has already added highlight_thicknesses.)
905 */
906 newstw->core.height = stp->TextRect.height
907 + (2 * stp->internal_height)
908 + (2 * newstw->primitive.highlight_thickness);
909 }
910 }
911
912
ProcessBackslashes(output,input)913 static void ProcessBackslashes(output,input)
914 char *output, *input;
915 {
916 char *out, *in;
917
918 out = output;
919 in = input;
920 while(*in)
921 if (*in == '\\')
922 {
923 in++;
924 switch (*in)
925 {
926 case 'n':
927 *out++ = '\n';
928 break;
929 case 't':
930 *out++ = '\t';
931 break;
932 case 'b':
933 *out++ = '\b';
934 break;
935 case 'r':
936 *out++ = '\r';
937 break;
938 case 'f':
939 *out++ = '\f';
940 break;
941 default:
942 *out++ = '\\';
943 *out++ = *in;
944 break;
945 }
946 in++;
947 }
948 else
949 *out++ = *in++;
950 *out = '\0';
951 }
952
953 /*************************************<->*************************************
954 *
955 * static void Initialize (request, new)
956 * Widget request, new;
957 *
958 * Description:
959 * -----------
960 * See XToolKit Documentation
961 *
962 *
963 * Inputs:
964 * ------
965 *
966 * Outputs:
967 * -------
968 *
969 * Procedures Called
970 * -----------------
971 * Xmalloc
972 * ProcessBackslashes
973 * XwStrlen
974 * SetSize
975 *
976 *************************************<->***********************************/
Initialize(req,new)977 static void Initialize (req, new)
978 XwStaticTextWidget req, new;
979 {
980 char *s;
981
982 new->static_text.output_string = NULL;
983
984 if (new->static_text.input_string != NULL)
985 {
986
987 /*
988 * Copy the input string into local space.
989 */
990 s = XtMalloc(XwStrlen(new->static_text.input_string)+1);
991 ProcessBackslashes(s,new->static_text.input_string);
992 new->static_text.input_string = s;
993 }
994
995 ValidateInputs(new);
996 new->core.width = req->core.width;
997 new->core.height = req->core.height;
998 SetSize(new);
999 }
1000
1001
1002 /*************************************<->*************************************
1003 *
1004 * static Boolean SetValues(current, request, new, last)
1005 * XwStaticTextWidget current, request, new;
1006 * Boolean last;
1007 *
1008 * Description:
1009 * -----------
1010 * See XToolKit Documentation
1011 *
1012 *
1013 * Inputs:
1014 * ------
1015 *
1016 * Outputs:
1017 * -------
1018 *
1019 * Procedures Called
1020 * -----------------
1021 * ValidateInputs
1022 * strcmp
1023 * SetSize
1024 * SetNormalGC
1025 *
1026 *************************************<->***********************************/
SetValues(current,request,new,last)1027 static Boolean SetValues(current, request, new, last)
1028 XwStaticTextWidget current, request, new;
1029 Boolean last;
1030 {
1031 Boolean flag = FALSE;
1032 Boolean newstring = FALSE;
1033 Boolean layoutchanges = FALSE;
1034 Boolean otherchanges = FALSE;
1035 char *newstr, *curstr;
1036 char *s;
1037 XwStaticTextPart *newstp, *curstp;
1038 int new_w, new_h;
1039
1040 newstp = &(new->static_text);
1041 curstp = &(current->static_text);
1042 if (newstp->input_string != curstp->input_string)
1043 {
1044 newstring = TRUE;
1045 /*
1046 * Copy the input string into local space.
1047 */
1048 s = XtMalloc(XwStrlen(newstp->input_string)+1);
1049 ProcessBackslashes(s,new->static_text.input_string);
1050 /*
1051 * Deallocate the old string.
1052 */
1053 XtFree(curstp->input_string);
1054 /*
1055 * Have everybody point to the new string.
1056 */
1057 newstp->input_string = s;
1058 curstp->input_string = s;
1059 request->static_text.input_string = s;
1060 }
1061
1062 ValidateInputs(new);
1063
1064 if ((newstring) ||
1065 (newstp->font != curstp->font) ||
1066 (newstp->internal_height != curstp->internal_height) ||
1067 (newstp->internal_width != curstp->internal_width) ||
1068 ((new->core.width <= 0) || (new->core.height <= 0)) ||
1069 (request->core.width != current->core.width) ||
1070 (request->core.height != current->core.height))
1071 {
1072 if (request->primitive.recompute_size)
1073 {
1074 if (request->core.width == current->core.width)
1075 new->core.width = 0;
1076 if (request->core.height == current->core.height)
1077 new->core.height = 0;
1078 }
1079
1080 /*
1081 * Call SetSize to get the new size.
1082 */
1083 SetSize(new);
1084
1085 /*
1086 * Save changes that SetSize does to the layout.
1087 */
1088 new_w = new->core.width;
1089 new_h = new->core.height;
1090 /*
1091 * In case our parent won't let us change size we must
1092 * now restore the widget to the current size.
1093 */
1094 new->core.width = current->core.width;
1095 new->core.height = current->core.height;
1096 SetSize(new);
1097 /*
1098 * Reload new with the new sizes in order cause XtSetValues
1099 * to invoke our parent's geometry management procedure.
1100 */
1101 new->core.width = new_w;
1102 new->core.height = new_h;
1103
1104 flag = TRUE;
1105 }
1106
1107 if ((new->primitive.foreground !=
1108 current->primitive.foreground) ||
1109 (new->core.background_pixel !=
1110 current->core.background_pixel) ||
1111 (newstp->font != curstp->font))
1112 {
1113 if (XtIsRealized((Widget)new))
1114 {
1115 XFreeGC(XtDisplay(new),new->static_text.normal_GC);
1116 SetNormalGC(new);
1117 }
1118 flag = TRUE;
1119 }
1120
1121 return(flag);
1122 }
1123
1124
1125 /*************************************<->*************************************
1126 *
1127 * static void Realize(w , valueMask, attributes)
1128 * Widget w;
1129 * XtValueMask *valueMask;
1130 * XSetWindowAttributes *attributes;
1131 *
1132 * Description:
1133 * -----------
1134 * See XToolKit Documentation
1135 *
1136 * Inputs:
1137 * ------
1138 *
1139 * Outputs:
1140 * -------
1141 *
1142 * Procedures Called
1143 * -----------------
1144 * XtCreateWindow
1145 * SetNormalGC
1146 *
1147 *************************************<->***********************************/
Realize(stw,valueMask,attributes)1148 static void Realize(stw , valueMask, attributes)
1149 XwStaticTextWidget stw;
1150 XtValueMask *valueMask;
1151 XSetWindowAttributes *attributes;
1152 {
1153
1154 XtCreateWindow((Widget)stw,InputOutput,(Visual *) CopyFromParent,
1155 *valueMask,attributes);
1156 SetNormalGC(stw);
1157 _XwRegisterName(stw);
1158 }
1159
1160
1161 /*************************************<->*************************************
1162 *
1163 * static void Destroy(stw)
1164 * XwStaticTextWidget stw;
1165 *
1166 * Description:
1167 * -----------
1168 * See XToolKit Documentation
1169 *
1170 * Inputs:
1171 * ------
1172 *
1173 * Outputs:
1174 * -------
1175 *
1176 * Procedures Called
1177 * -----------------
1178 * XtFree
1179 * XFreeGC
1180 *
1181 *************************************<->***********************************/
Destroy(stw)1182 static void Destroy(stw)
1183 XwStaticTextWidget stw;
1184 {
1185 XtFree(stw->static_text.input_string);
1186 XtFree(stw->static_text.output_string);
1187 if (XtIsRealized((Widget)stw))
1188 {
1189 XFreeGC(XtDisplay(stw),stw->static_text.normal_GC);
1190 }
1191 }
1192
1193
1194 /*************************************<->*************************************
1195 *
1196 * static void Redisplay(stw)
1197 * XwStaticTextWidget stw;
1198 *
1199 * Description:
1200 * -----------
1201 * See XToolKit Documentation
1202 *
1203 * Inputs:
1204 * ------
1205 *
1206 * Outputs:
1207 * -------
1208 *
1209 * Procedures Called
1210 * -----------------
1211 * XTextExtents
1212 * XDrawString
1213 * XtWarning
1214 *
1215 *************************************<->***********************************/
Redisplay(stw)1216 static void Redisplay(stw)
1217 XwStaticTextWidget stw;
1218 {
1219 GC normal_GC;
1220 int i;
1221 int cur_x, cur_y; /* Current start of baseline */
1222 int y_delta; /* Absolute space between baselines */
1223 int x_delta; /* For left bearing of the first char in a line */
1224 int dir, asc, desc; /* Junk parameters for XTextExtents */
1225 char *str1, *str2, *str3;
1226 XFontStruct *font;
1227 XCharStruct overall;
1228 XRectangle *ClipRect;
1229 XwStaticTextPart *stp;
1230
1231 /*
1232 * This is to save typing for me and
1233 * pointer arithmetic for the machine.
1234 */
1235 stp = &(stw->static_text);
1236 str1 = str2 = stp->output_string;
1237 font = stp->font;
1238 normal_GC = stp->normal_GC;
1239 ClipRect = &(stp->TextRect);
1240
1241 if (XtIsRealized((Widget)stw))
1242 XClearArea(XtDisplay(stw),XtWindow(stw),
1243 0,0,stw->core.width,stw->core.height,FALSE);
1244
1245 /*
1246 * We don't get to start drawing at the top of the text box.
1247 * See X11 font manual pages.
1248 */
1249 cur_y = ClipRect->y + font->ascent;
1250
1251 /*
1252 * Set up the total line spacing.
1253 */
1254 y_delta = ((stp->line_space / 100.0) + 1) * (font->descent + font->ascent);
1255
1256 switch (stp->alignment)
1257 {
1258 case XwALIGN_LEFT:
1259 cur_x = ClipRect->x;
1260 while(*str1)
1261 {
1262 /*
1263 * Left alignment strips leading blanks.
1264 */
1265 if (stp->strip)
1266 while(*str1 == ' ')
1267 str1++;
1268 str2 = str1;
1269 /*
1270 * Look for a newline and count characters.
1271 */
1272 for(i=0; ((*str1 != '\n') && *str1); i++, str1++);
1273 /*
1274 * Did we get anything?
1275 */
1276 if (i)
1277 {
1278 /*
1279 * Handle the left bearing of the first char
1280 * in this substring.
1281 */
1282 XTextExtents(font,str2,1,&dir,&asc,&desc,
1283 &overall);
1284 x_delta = overall.lbearing;
1285 /*
1286 * Write to the window
1287 */
1288 XDrawString(XtDisplay(stw),XtWindow(stw),
1289 normal_GC,(cur_x + x_delta),cur_y,str2,i);
1290 x_delta = overall.lbearing = 0;/* I'm paranoid...*/
1291 }
1292 /*
1293 * Move to the next line.
1294 */
1295 cur_y += y_delta;
1296 if (*str1)
1297 str1++; /* Step past the \n */
1298 }
1299 break;
1300 case XwALIGN_CENTER:
1301 cur_x = ClipRect->x + (ClipRect->width / 2);
1302 while(*str1)
1303 {
1304 /*
1305 * Strip leading blanks.
1306 */
1307 if (stp->strip)
1308 while(*str1 == ' ')
1309 str1++;
1310 str2 = str1;
1311 for(i=0; ((*str1 != '\n') && *str1); i++, str1++);
1312 /*
1313 * Strip trailing blanks.
1314 */
1315 if (stp->strip)
1316 {
1317 str3 = str1;
1318 str3--;
1319 while (*str3 == ' ')
1320 i--, str3--;
1321 }
1322 if (i)
1323 {
1324 /*
1325 * Center the substring.
1326 */
1327 x_delta = XTextWidth(font,str2,i) / 2;
1328 XDrawString(XtDisplay(stw),XtWindow(stw),
1329 normal_GC,(cur_x - x_delta),cur_y,str2,i);
1330 x_delta = 0; /* ... still paranoid...*/
1331 }
1332 cur_y += y_delta;
1333 if (*str1)
1334 str1++; /* Step past the \n */
1335 }
1336 break;
1337 case XwALIGN_RIGHT:
1338 cur_x = ClipRect->x + ClipRect->width;
1339 while(*str1)
1340 {
1341 str2 = str1;
1342 for(i=0; ((*str1 != '\n') && *str1); i++, str1++);
1343 /*
1344 * Strip trailing blanks.
1345 */
1346 if (stp->strip)
1347 {
1348 str3 = str1;
1349 str3--;
1350 while (*str3 == ' ')
1351 i--, str3--;
1352 }
1353 if (i)
1354 {
1355 XDrawString(XtDisplay(stw),XtWindow(stw),
1356 normal_GC,
1357 (cur_x - XTextWidth(font,str2,i)),
1358 cur_y,str2,i);
1359 }
1360 cur_y += y_delta;
1361 if (*str1)
1362 str1++; /* Step past the \n */
1363 }
1364 break;
1365 default:
1366 /*
1367 * How did we get here?
1368 */
1369 XtWarning("XwStaticTextWidget: An Unknown Alignment has crept into the code\n");
1370 break;
1371 }
1372
1373 /*
1374 * We don't want to lose the highlight on redisplay
1375 * do we?
1376 */
1377 if (stw->primitive.highlighted)
1378 {
1379 _XwHighlightBorder(stw);
1380 stw->primitive.display_highlighted = TRUE;
1381 }
1382 else
1383 if (stw->primitive.display_highlighted)
1384 {
1385 _XwUnhighlightBorder(stw);
1386 stw->primitive.display_highlighted = FALSE;
1387 }
1388
1389 }
1390
1391 /*************************************<->*************************************
1392 *
1393 * static void Resize(stw)
1394 * XwStaticTextWidget stw;
1395 *
1396 * Description:
1397 * -----------
1398 * See XToolKit Documentation
1399 *
1400 * Inputs:
1401 * ------
1402 *
1403 * Outputs:
1404 * -------
1405 *
1406 * Procedures Called
1407 * -----------------
1408 * SetSize
1409 * XSetClipRectangles
1410 *
1411 *************************************<->***********************************/
Resize(stw)1412 static void Resize(stw)
1413 XwStaticTextWidget stw;
1414 {
1415 XRectangle ClipRect;
1416
1417 /*
1418 * Same as at initialization except just look at the new widget.
1419 */
1420 SetSize(stw);
1421
1422 if (XtIsRealized((Widget)stw))
1423 {
1424 /*
1425 * Set the Clip Region.
1426 */
1427 ClipRect.width = stw->core.width -
1428 (2 * (stw->static_text.internal_width +
1429 stw->primitive.highlight_thickness));
1430 ClipRect.height = stw->core.height -
1431 (2 * (stw->static_text.internal_height +
1432 stw->primitive.highlight_thickness));
1433 ClipRect.x = stw->primitive.highlight_thickness +
1434 stw->static_text.internal_width;
1435 ClipRect.y = stw->primitive.highlight_thickness +
1436 stw->static_text.internal_height;
1437
1438 XSetClipRectangles(XtDisplay(stw),stw->static_text.normal_GC,
1439 0,0, &ClipRect,1,Unsorted);
1440 }
1441 }
1442
1443
1444
1445
1446 /****************************************************************
1447 *
1448 * Event Routines.
1449 *
1450 * Select - Call the callback when the left button goes down.
1451 *
1452 * Release - Call the callback when the left button goes up.
1453 *
1454 ****************************************************************/
1455
Select(w,event)1456 static void Select(w,event)
1457 XwStaticTextWidget w;
1458 XEvent *event;
1459 {
1460 XtCallCallbacks((Widget)w,XtNselect,event);
1461 }
1462
Release(w,event)1463 static void Release(w,event)
1464 XwStaticTextWidget w;
1465 XEvent *event;
1466 {
1467 XtCallCallbacks((Widget)w,XtNrelease,event);
1468 }
1469
Toggle(w,event)1470 static void Toggle(w,event)
1471 XwStaticTextWidget w;
1472 XEvent *event;
1473 {
1474 }
1475