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