\input wbuildmac.tex
\Class{XfwfLabel}
 The Label class has the capability to display one or more lines of
text in a single font. Otherwise it is the same as the Board class.
The text can be left, right or center justified and it can be centered
vertically or put against the top or the bottom of the widget.

The text is `grayed out' when the widget becomes insensitive
(resource: {\tt sensitive}), even though a Label widget has no actions of
its own.





\Publicvars
\Table{XfwfLabel}
XtNlabel&XtCLabel&String &NULL \cr
XtNfont&XtCFont&FontStruct&XtDefaultFont \cr
XtNforeground&XtCForeground&Pixel &XtDefaultForeground \cr
XtNalignment&XtCAlignment&Alignment &0 \cr
XtNmargin&XtCMargin&Int &2 \cr
XtNshrinkToFit&XtCShrinkToFit&Boolean &False \cr
\endTable
\Section
\Publicvar{XtNlabel}
 The text is a single string, which may contain embedded newlines.
There is no provision for changing fonts in the middle of a text.



\HCode
\Code
String  label = NULL \endCode
\endHCode


\Section
\Publicvar{XtNfont}
 The text is drawn in the font which is give as the {\tt font} resource.



\HCode
\Code
{\langle}FontStruct{\rangle} XFontStruct * font = {\langle}String{\rangle}XtDefaultFont \endCode
\endHCode


\Section
\Publicvar{XtNforeground}
 The foreground color is the color used to draw the text.



\HCode
\Code
Pixel  foreground = {\langle}String{\rangle}XtDefaultForeground \endCode
\endHCode


\Section
\Publicvar{XtNalignment}
 The text can be aligned in the widget in nine ways: left, right or
center, combined with top, center or bottom. Symbolic constants
{\tt XfwfTop}, {\tt XfwfBottom}, {\tt XfwfLeft} and {\tt XfwfRight} can be added together to
get the desired alignment.  The alignment is actually a four-bit
number made up of two parts of 2 bits added together: 1 is left, 2 is
right, 0 is center, 4 is top, 8 is bottom, 0 is vertical center. Thus
5 (= 1 + 4) means top left and 2 (= 2 + 0) means center right. For
easier specification, there is also a converter from strings, that
accepts string like `top left' or `center right'.



\HCode
\Code
Alignment  alignment = 0 \endCode
\endHCode


\Section
\Publicvar{XtNmargin}
 The {\tt margin} is only used when the text is not centered. It gives
the number of pixels between the frame and the text.



\HCode
\Code
int  margin = 2 \endCode
\endHCode


\Section
\Publicvar{XtNshrinkToFit}
 Buttons will normally not occupy the full area of their parents.
Most likely they will be a fixed size or a size depending on the
label. By setting the {\tt shrinkToFit} resource to True, the width and
height are recomputed with every new label.



\HCode
\Code
Boolean  shrinkToFit = False \endCode
\endHCode


\End\Table{XfwfBoard}
XtNcursor&XtCCursor&Cursor &None \cr
XtNabs{\underline}x&XtCAbs{\underline}x&Int &0 \cr
XtNrel{\underline}x&XtCRel{\underline}x&Float &"0.0"\cr
XtNabs{\underline}y&XtCAbs{\underline}y&Int &0 \cr
XtNrel{\underline}y&XtCRel{\underline}y&Float &"0.0"\cr
XtNabs{\underline}width&XtCAbs{\underline}width&Int &0 \cr
XtNrel{\underline}width&XtCRel{\underline}width&Float &"1.0"\cr
XtNabs{\underline}height&XtCAbs{\underline}height&Int &0 \cr
XtNrel{\underline}height&XtCRel{\underline}height&Float &"1.0"\cr
XtNhunit&XtCHunit&Int &1 \cr
XtNvunit&XtCVunit&Int &1 \cr
XtNlocation&XtCLocation&String &NULL \cr
\endTable
\Table{XfwfFrame}
XtNframeType&XtCFrameType&FrameType &XfwfRaised \cr
XtNframeWidth&XtCFrameWidth&Dimension &0 \cr
XtNframeOffset&XtCFrameOffset&Dimension &0 \cr
XtNshadowScheme&XtCShadowScheme&ShadowScheme &XfwfAuto \cr
XtNlightColor&XtCLightColor&Pixel &XtDefaultBackground \cr
XtNdarkColor&XtCDarkColor&Pixel &XtDefaultForeground \cr
XtNlightStipple&XtCLightStipple&Bitmap &NULL \cr
XtNdarkStipple&XtCDarkStipple&Bitmap &NULL \cr
\endTable
\Table{XfwfCommon}
XtNhighlighted&XtCHighlighted&Boolean &False \cr
XtNselected&XtCSelected&Boolean &False \cr
XtNtext&XtCText&String &NULL \cr
XtNhandlers&XtCHandlers&Program *&NULL \cr
\endTable
\Table{Composite}
XtNchildren&XtCChildren&WidgetList &NULL \cr
insertPosition&XtCInsertPosition&XTOrderProc &NULL \cr
numChildren&XtCNumChildren&Cardinal &0 \cr
\endTable
\Table{Core}
XtNx&XtCX&Position &0 \cr
XtNy&XtCY&Position &0 \cr
XtNwidth&XtCWidth&Dimension &0 \cr
XtNheight&XtCHeight&Dimension &0 \cr
borderWidth&XtCBorderWidth&Dimension &0 \cr
XtNcolormap&XtCColormap&Colormap &NULL \cr
XtNdepth&XtCDepth&Int &0 \cr
destroyCallback&XtCDestroyCallback&XTCallbackList &NULL \cr
XtNsensitive&XtCSensitive&Boolean &True \cr
XtNtranslations&XtCTranslations&XTTranslations &NULL \cr
ancestorSensitive&XtCAncestorSensitive&Boolean &False \cr
accelerators&XtCAccelerators&XTTranslations &NULL \cr
borderColor&XtCBorderColor&Pixel &0 \cr
borderPixmap&XtCBorderPixmap&Pixmap &NULL \cr
background&XtCBackground&Pixel &0 \cr
backgroundPixmap&XtCBackgroundPixmap&Pixmap &NULL \cr
mappedWhenManaged&XtCMappedWhenManaged&Boolean &True \cr
XtNscreen&XtCScreen&Screen *&NULL \cr
\endTable
\Imports
\Section


\Code
{\incl} "stip4.bm"\endCode


\Section


\Code
{\incl} {\langle}stdio.h{\rangle}\endCode


\End\Privatevars
\Section
 For faster drawing, the number of lines in the text is stored in a
private variable by the {\tt set{\underline}values} and {\tt initialize} methods.



\Code
int  nlines\endCode


\Section
 For drawing the text, this GC is used.



\Code
GC  gc\endCode


\Section
 For graying out the text, another GC is used.



\Code
GC  graygc\endCode


\Section
 When the {\tt shrinkToFit} resource is set, we need the minimum area
necessary for the complete label to be visible.



\Code
Dimension  label{\underline}width\endCode


\Section


\Code
Dimension  label{\underline}height\endCode


\End\Methods
\Section
 The {\tt set{\underline}values} method checks the {\tt background} resource, because is
is used in the GC {\tt graygc}. When the text or the font change, the
private variables {\tt nlines}, {\tt label{\underline}height} and {\tt label{\underline}width} are
updated.



\Code
Boolean  set{\underline}values(Widget  old, Widget  request, {\dollar}, ArgList  args, Cardinal * num{\underline}args)
{\lbrace}
    Boolean need{\underline}redisplay = False;
    char *s;
    Dimension wd, ht;

    if ({\dollar}background{\underline}pixel != {\dollar}old{\dollar}background{\underline}pixel)
	make{\underline}graygc({\dollar});

    if ({\dollar}font != {\dollar}old{\dollar}font) {\lbrace}
	make{\underline}gc({\dollar});
	if ({\dollar}label != NULL) need{\underline}redisplay = True;
    {\rbrace}
    if ({\dollar}foreground != {\dollar}old{\dollar}foreground) {\lbrace}
	make{\underline}gc({\dollar});
	if ({\dollar}label != NULL) need{\underline}redisplay = True;
    {\rbrace}
    if ({\dollar}margin != {\dollar}old{\dollar}margin)
	if ({\dollar}label != NULL) need{\underline}redisplay = True;

    if ({\dollar}sensitive != {\dollar}old{\dollar}sensitive)
	if ({\dollar}label != NULL) need{\underline}redisplay = True;

    if ({\dollar}label != {\dollar}old{\dollar}label) {\lbrace}
	count{\underline}lines({\dollar});
	need{\underline}redisplay = True;
    {\rbrace}
    if (need{\underline}redisplay {\ampersand}{\ampersand} {\dollar}shrinkToFit) {\lbrace}
	{\dollar}rel{\underline}width = {\dollar}rel{\underline}height = 0.0;
	wd = {\dollar}label{\underline}width + 2 * ({\dollar}margin + {\dollar}frameWidth + {\dollar}frameOffset);
	ht = {\dollar}label{\underline}height + 2 * ({\dollar}margin + {\dollar}frameWidth + {\dollar}frameOffset);
	if (wd != {\dollar}width {\bar}{\bar} ht != {\dollar}height) {\lbrace}
	    {\dollar}width = {\dollar}abs{\underline}width = wd;
	    {\dollar}height = {\dollar}abs{\underline}height = ht;
	    need{\underline}redisplay = False;
	{\rbrace}
	(void) fprintf(stderr, "{\percent}s ({\percent}ld): (Label) new size {\percent}d x {\percent}d{\backslash}n",
		       XtName({\dollar}), {\dollar}, wd, ht);
    {\rbrace}
    return need{\underline}redisplay;
{\rbrace}\endCode


\Section
 The {\tt initialize} methods creates the first GC's and initializes the
private variables. It sets the GC's to {\tt NULL} and calls two utility
routines to actually create them.



\Code
initialize(Widget  request, {\dollar}, ArgList  args, Cardinal * num{\underline}args)
{\lbrace}
    char *s;
    Dimension wd, ht;

    count{\underline}lines({\dollar});
    {\dollar}gc = NULL;
    make{\underline}gc({\dollar});
    {\dollar}graygc = NULL;
    make{\underline}graygc({\dollar});
    if ({\dollar}shrinkToFit) {\lbrace}
	wd = {\dollar}label{\underline}width + 2 * ({\dollar}margin + {\dollar}frameWidth + {\dollar}frameOffset);
	ht = {\dollar}label{\underline}height + 2 * ({\dollar}margin + {\dollar}frameWidth + {\dollar}frameOffset);
	XtVaSetValues
	    ({\dollar}, XtVaTypedArg, XtNrel{\underline}width, XtRString, "0.0", 4,
	     XtNabs{\underline}width, wd, XtVaTypedArg, XtNrel{\underline}height, XtRString,
	     "0.0", 4, XtNabs{\underline}height, ht, NULL);
    {\rbrace}
{\rbrace}\endCode


\Section
 The {\tt expose} method is responsible for drawing the text. The text is
put in the position given in {\tt alignment}. The text is always kept
within the frame. If necessary, the text is clipped. The routine ends
by calling the {\tt expose} method from the superclass, which is
responsible for drawing the frame.



\Code
expose({\dollar}, XEvent * event, Region  region)
{\lbrace}
    Region reg;
    XRectangle rect;
    int baseline;
    Dimension w;
    char *s, *t;
    int x, y;

    if (! XtIsRealized({\dollar})) return;
    if ({\dollar}label != NULL) {\lbrace}
	baseline = {\dollar}font-{\rangle}ascent + {\dollar}font-{\rangle}descent;
	{\dollar}compute{\underline}inside({\dollar}, {\ampersand}rect.x, {\ampersand}rect.y, {\ampersand}rect.width, {\ampersand}rect.height);
	rect.x += {\dollar}margin;  rect.width -= 2 * {\dollar}margin;
	rect.y += {\dollar}margin;  rect.height -= 2 * {\dollar}margin;
	if (region != NULL) {\lbrace}
	    reg = XCreateRegion();
	    XUnionRectWithRegion({\ampersand}rect, reg, reg);
	    XIntersectRegion(region, reg, reg);
	    XSetRegion(XtDisplay({\dollar}), {\dollar}gc, reg);
	{\rbrace}
	if ({\dollar}alignment {\ampersand} XfwfTop)
	    y = rect.y + {\dollar}font-{\rangle}ascent;
	else if ({\dollar}alignment {\ampersand} XfwfBottom)
	    y = rect.y + rect.height - {\dollar}nlines * baseline + {\dollar}font-{\rangle}ascent;
	else
	    y = rect.y + (rect.height - {\dollar}nlines * baseline)/2 + {\dollar}font-{\rangle}ascent;
	for (s = {\dollar}label, t = s; *s; s++) {\lbrace}
	    if (*s == '{\backslash}n') {\lbrace}
		w = XTextWidth({\dollar}font, t, s - t);
		if ({\dollar}alignment {\ampersand} XfwfLeft) x = rect.x;
		else if ({\dollar}alignment {\ampersand} XfwfRight) x = rect.x + rect.width - w;
		else x = rect.x + (rect.width - w)/2;
		XDrawString(XtDisplay({\dollar}), XtWindow({\dollar}), {\dollar}gc, x, y, t, s - t);
		t = s + 1;
		y += baseline;
	    {\rbrace}
	{\rbrace}
	w = XTextWidth({\dollar}font, t, s - t);
	if ({\dollar}alignment {\ampersand} XfwfLeft) x = rect.x;
	else if ({\dollar}alignment {\ampersand} XfwfRight) x = rect.x + rect.width - w;
	else x = rect.x + (rect.width - w)/2;
	XDrawString(XtDisplay({\dollar}), XtWindow({\dollar}), {\dollar}gc, x, y, t, s - t);
	if (region != NULL) XSetClipMask(XtDisplay({\dollar}), {\dollar}gc, None);
	if (! {\dollar}sensitive) {\lbrace}
	    if (region != NULL) XSetRegion(XtDisplay({\dollar}), {\dollar}graygc, reg);
	    XFillRectangle(XtDisplay({\dollar}), XtWindow({\dollar}), {\dollar}graygc, rect.x,
			   rect.y, rect.width, rect.height);
	    if (region != NULL) XSetClipMask(XtDisplay({\dollar}), {\dollar}graygc, None);
	{\rbrace}
    {\rbrace}
    {\hashmark}expose({\dollar}, event, region);
{\rbrace}\endCode


\End\Utilities
\Section
 The {\tt make{\underline}gc} routine creates the GC for the text. 



\Code
make{\underline}gc({\dollar})
{\lbrace}
    XtGCMask mask;
    XGCValues values;

    if ({\dollar}gc != NULL) XtReleaseGC({\dollar}, {\dollar}gc);
    values.foreground = {\dollar}foreground;
    values.font = {\dollar}font-{\rangle}fid;
    mask = GCFont {\bar} GCForeground;
    {\dollar}gc = XtGetGC({\dollar}, mask, {\ampersand}values);
{\rbrace}\endCode


\Section
 The {\tt make{\underline}graygc} routine creates a GC for graying out the text. It
contains a stipple in the background color, that will be applied over
the text.



\Code
make{\underline}graygc({\dollar})
{\lbrace}
    XtGCMask mask;
    XGCValues values;

    if ({\dollar}graygc != NULL) XtReleaseGC({\dollar}, {\dollar}graygc);
    values.foreground = {\dollar}background{\underline}pixel;
    values.stipple =
	XCreateBitmapFromData(XtDisplay({\dollar}),
			      RootWindowOfScreen(XtScreen({\dollar})),
			      stip4{\underline}bits, stip4{\underline}width, stip4{\underline}height);
    values.fill{\underline}style = FillStippled;
    mask = GCForeground {\bar} GCStipple {\bar} GCFillStyle;
    {\dollar}graygc = XtGetGC({\dollar}, mask, {\ampersand}values);
{\rbrace}\endCode


\Section
 The funtion {\tt count{\underline}lines} computes the correct values for the
private variables {\tt nlines}, {\tt label{\underline}width} and {\tt label{\underline}height}.



\Code
count{\underline}lines({\dollar})
{\lbrace}
    String p, s;
    Dimension w;

    {\dollar}nlines = 0;
    {\dollar}label{\underline}width = 0;
    if ({\dollar}label) {\lbrace}
	for (p = {\dollar}label, {\dollar}nlines = 1, s = {\dollar}label; *s; s++) {\lbrace}
	    if (*s == '{\backslash}n') {\lbrace}
		{\dollar}nlines++;
		w = XTextWidth({\dollar}font, p, s - p);
		p = s + 1;
		if (w {\rangle} {\dollar}label{\underline}width) {\dollar}label{\underline}width = w;
	    {\rbrace}
	{\rbrace}
	w = XTextWidth({\dollar}font, p, s - p);
	if (w {\rangle} {\dollar}label{\underline}width) {\dollar}label{\underline}width = w;
    {\rbrace}
    {\dollar}label{\underline}height = {\dollar}nlines * ({\dollar}font-{\rangle}ascent + {\dollar}font-{\rangle}descent);
{\rbrace}\endCode


\End\bye
