[comp.sources.x] v03i079: Xcu -- widget set from Cornell University, Part03/12

argv@island.uu.net (Dan Heller) (04/25/89)

Submitted-by: Gene Dykes <gdykes@tcgould.tn.cornell.edu>
Posting-number: Volume 3, Issue 79
Archive-name: xcu/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of archive 3 (of 12)."
# Contents:  doc/wlm_tutor.mm src/CuCommandI.h src/CuLabel.c
# Wrapped by argv@island on Mon Apr 24 15:41:31 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'doc/wlm_tutor.mm' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'doc/wlm_tutor.mm'\"
else
echo shar: Extracting \"'doc/wlm_tutor.mm'\" \(22935 characters\)
sed "s/^X//" >'doc/wlm_tutor.mm' <<'END_OF_FILE'
X.ll +5
X.PH ""
X.ce
XWLM TUTORIAL
X.sp
X.ta 0.25i 0.50i 0.75i 1.00i 1.25i 1.50i 1.75i 2.00i 2.25i 2.50i 2.75i 3.00i
XSuppose you want to make a small menu for a client application that is going
Xto rotate the color look up tables of your graphics box.
XYou want the menu to contain several items, not all visible at once: 
X.AL A
X.LI
XA page for LUT modification.
X.AL 1
X.LI
XA set of three buttons, each with the name of a LUT description file.
X.LI
XA one button toggle that converts the LUTs between negative and positive.
X.LE
X.LI
XA page for rotation control.
X.AL 1
X.LI
XA button to execute a single rotation increment.
X.LI
XA two button toggle that will control whether or not continuous
Xrotation is enabled.
X.LI
XA set of three buttons that indicate which color banks are enabled for rotation.
X.LI
XA label that shows the current LUT description file.
X.LE
X.LI
XAn ever-present pair of buttons that control which of the two pages is visible.
XThe two pages are to exactly overlay each other, so that only one is visible
Xat a time.
X.LE
X.P
XYou now have a choice - to write all the code yourself to handle this menu,
Xor to use the Widget Layout Manager (\fBCuWlm\fR) widget.
XWhen you have finished this tutorial, I hope to have convinced you that
Xthe \fBCuWlm\fR is the obvious choice.
X.P
XIn either case, the first task is to choose the widgets needed to accomplish the
Xrequired interaction.
XThese, of course, can come from a variety of toolkits.
XThe Xcu toolkit alone contains all the required widgets for this example.
X.P
XTo depict the hierarchy of widgets, we might picture it as follows,
Xusing typical C language curly braces and indentation:
X.sp
XCuWlm {
X.br
X	CuTbl {
X.br
X		CuDeck {
X.br
X			CuTbl {
X.br
X				RadioButtons{} /* file choices */
X.br
X				ToggleButton{} /* negative/positive */
X.br
X				}
X.br
X			CuTbl {
X.br
X				Command{}         /* rotation increment */
X.br
X				ToggleButtons{}   /* continuous rotation */
X.br
X				CheckBoxButtons{} /* red, green, blue */
X.br
X				Label{}           /* current file */
X.br
X				}
X.br
X			}
X.br
X		ToggleButtons{} /* page control */
X.br
X		}
X.br
X	}
X.sp
XThis is exactly the basic syntax for the
XWidget Layout Description Language (WLDL) -- a widget class name with
Xthe body of the widget enclosed in curly braces.
XAll that is left is the grammar for the two types of things that the
Xbody of a widget may contain: resources and directives.
XIn the following examples, \fBbold\fR indicates keywords in the grammar,
X\fIitalics\fR indicate strings which are to be substituted by the programmer,
Xand words in regular font indicate sample substitutions.
X.sp
XTo take the \fBCuLabel\fR widget as an example, one can modify the \fBXtNlabel\fR
Xresource merely by specifying the resource name and the resource value as a
Xpair, with the value in double quotes:
X.sp
XCuLabel { label "File 1" }
X.sp
X.P
XIt is also possible to change the default resources for all widgets
Xin the subtree rooted at the widget in which a default resource specification
Xoccurs.  For example, to change all the background colors for the widgets
Xbeneath a \fBCuTbl\fR, use a default specification and a resource value:
X.sp
XCuTbl {
X.br
X	*Background "yellow"
X.br
X	\fIchildren\fR
X.br
X	}
X.sp
XThe default specification must begin with a "*" and has the same syntax
Xas the specifications found in a resource file. (The value for the resource,
Xhowever, is found between double quotes.
XIt is not separated from the specification by a colon.)
X.P
XThe other thing that a widget may contain is a directive.
XDirectives are a mechanism by which widgets may communicate with each other.
XThe messages are controlled by the \fBCuWlm\fR, thus
Xa programmer may implement complex menu semantics with the WLDL instead
Xof client code.
XDirectives are executed in response to widget callbacks, and are only
Xexecuted if the call_data in the callback matches a trigger.
XThe action taken can be either to modify a widget's resource with
X\fBXtSetValues()\fR or to call a widget's public function.
XGrammatically, a directive is of the form:
X.sp
X	\fBif\fR \fIcallback_name\fR ( \fItrigger\fR ) \fIaction\fR
X.sp
XWe will need several directives in our example.
XFor instance, when the user clicks on a new filename while in the modification
Xpage, we will want to change the label of the \fBCuLabel\fR widget in the
Xrotation control page.
XThis is easily accomplished by putting this directive in the body of the
Xappropriate widget:
X.sp
X\fBif\fR callback ()
X.br
X	\fBXtSetValues\fR ( \fIwidget_class\fR "\fIwidget_name\fR",
X\fIresource_name\fR, "\fIresource_value\fR" )
X.sp
XSince there is no trigger, the action is always taken.
X.P
XWe will also need the kind of directive that calls a widget's public function.
XIn our example, when the user clicks on a button to change pages, the proper
Xpage can be placed on top by calling the \fBCuDeckRaiseWidget()\fR procedure
Xof the \fBCuDeck\fR widget:
X.sp
X\fIWidget_class\fR {
X.br
X	...
X.br
X	\fBif\fR callback ()
X.br
X		RaiseWidget ( CuDeck "\fIdeck_name\fR",
X\fIdeck_child_class\fR "\fIdeck_child_name\fR" ) ;
X.br
X	}
X.sp
XNote that this directive has the same form as the first directive we looked at.
XThe only difference is that the action is a public
Xprocedure name instead of \fBXtSetValues()\fR.
XThe arguments are separated by commas, and the \fBCuWlm\fR takes care of
Xconverting them to the real values needed.
X.P
XNow we need an example without an empty trigger.
XSuppose we wanted something to happen based on a page's appearance
Xat the top of the \fBCuDeck\fR.
XThis could be handled this way:
X.sp
XCuDeck {
X.br
X	...
X.br
X	\fBif\fR callback
X( \fIwidget_class\fR "\fIwidget_name\fR" == x[0] ) \fIaction\fR
X.br
X	}
X.sp
X.P
XTo understand a trigger, one must understand what the value of the callback's
Xcall_data is.
XIn the case of the \fBCuDeck\fR widget, the call_data is an array of widgets.
XThe order of the widgets within the array represents their current stacking
Xorder.
XSo, this trigger says that when the specified widget is at the top of the
Xstacking order, the function should be called.
X.P
XMany widgets will have callbacks that are simpler values, such as an integer.
XIf one wanted to execute a directive when the call_data of a callback was less
Xthan 10, for example:
X.sp
X\fIWidget_class\fR {
X.br
X	...
X.br
X	\fBif\fR callback ( x  <  Int "10" ) \fIaction\fR
X.br
X	}
X.sp
X.P
XThe general form of a trigger is:
X.sp
X	\fIRepresentation_type\fR "\fIvalue\fR" 
X\fIcomparison_operator\fR  \fIcall_data\fR
X.br
X				or
X.br
X	\fIcall_data\fR  \fIcomparison_operator\fR  \fIRepresentation_type\fR "\fIvalue\fR"
X.sp
XNote that the call_data variable has to have a name, but the use of
Xthe name "x" is arbitrary.
X.P
XThere may also be more than one condition separated by logical operators:
X.sp
X\fIWidget_class\fR {
X.br
X	...
X.br
X	\fBif\fR callback ( x  >  Int "5"  &&  x  <  Int "10" ) \fIaction\fR
X.br
X	}
X.sp
X.P
XWe now have all the grammar necessary to layout the menu.
XNow we need to find out how communication between the menu and the client
Xcan be achieved.
XThis is accomplished with the \fBCuWlm\fR widget's public functions.
XSuppose the client has a routine that, when called, will perform one
Xrotation increment.
XAll we need to do is to add this procedure to the callback
Xlist of the \fBCuCommand\fR
Xbutton:
X.DS
XCuWlmAddCallback ( \fIwlm_id\fR,  \fItype\fR,
X		\fIwidget_class\fR,  \fIwidget_name\fR,
X		\fIcallback_name\fR,  \fIcallback\fR,  \fIclient_data\fR )
X.DE
XThe last 5 arguments are identical to the arguments needed by
X\fBXtAddCallback()\fR
X(\fIwidget_class\fR and \fIwidget_name\fR
Xget converted to the widget id), and the first
Xargument is the \fBCuWlm\fR widget id.
XThe only argument that needs some explanation is the second argument, and we'll
Xdefer that discussion to later.
X.P
XConsider the button that controls whether or not the LUTs should display
Xpositive or negative color.
XNormally, one would write a callback routine and register
Xit with a \fBCuCommand\fR widget.
XThis callback routine would then flip the value of a Boolean variable between
XTrue and False.
XThe \fBCuWlm\fR, however,  has public functions that can modify a client variable.
XBy choosing a widget that knows how to toggle between two states and has
Xa callback list for each state, the following two function calls, executed once,
Xwill ensure that the client variable reflects the state of the menu button:
X.DS
XCuWlmSetBoolean  ( wlm_id,  CuWlmSampling,  "CuBmgr",  "+-",  "setCallback",  &value,  True ) ;
XCuWlmSetBoolean  ( wlm_id,  CuWlmSampling,  "CuBmgr",  "+-",  "unsetCallback",  &value,  False ) ;
X.DE
XEach of these functions tells the \fBCuWlm\fR to store the value given in the
Xlast argument at the address given in the preceding argument whenever the
Xindicated callback is made by the widget.
XSo, what happens here is that whenever the button is clicked by the user,
Xthe widget
Xchanges state and calls the callbacks in one of its two callback lists.
XIn either case, the \fBCuWlm\fR has registered a callback with the widget,
Xand this callback assigns the appropriate value to the variable.
XFurthermore, since the second argument has been set to \fBCuWlmSampling\fR,
Xthe widget will be instructed to make the appropriate callback to indicate
Xits initial state, which will in turn initialize the client variable.
XThis ensures that the state of the client accurately reflects what the
Xuser sees in the appearance of the menu.
XSimilar public functions exist for "Int", "Float", and "String".
X.P
XThere are also four "Get" functions similar to the "Set" functions which
Xretrieve values from the call_data of the widget callback, for example:
X.DS
XCuWlmGetInt  ( wlm_id,  CuWlmSampling,  "CuBmgr",  "temperature",  "callback",  &value ) ;
X.DE
XThis function tells the \fBCuWlm\fR to take the integer value returned as
Xthe widget's callback data and store it at the indicated address.
X.P
XTaken together, all of these public functions discussed so far 
Xare called "Associations", in that they associate user activity
Xin the menu with actions in the client program.
XWe will use the term \fIWEvent\fR to indicate the activity of the \fBCuWlm\fR
Xwhen one of the callback routines registered as a result of an
XAssociation is called by a widget.
XA queue of pending \fIWEvents\fR is maintained by the \fBCuWlm\fR until the 
Xclient requests that they be executed.
X.P
XThe final set of \fBCuWlm\fR public functions deals with how to control when
X\fIWEvents\fR are to be executed.
XFor this purpose, there are three functions which make the \fBCuWlm\fR look
Xlike an input device.
X.BL
X.LI
X\fBCuWlmRequest ( wlm_id )\fR will block until a \fBWEvent\fR
Xis available in the queue, then executes it and returns.
X.LI
X\fBCuWlmEvent ( wlm_id )\fR checks the queue to see if there is a \fIWEvent\fR
Xpending.  If there is, it executes it and returns True.
XIf there is no \fIWEvent\fR pending, then it immediately returns False.
X.LI
X\fBCuWlmSample ( wlm_id )\fR will initiate a \fIWEvent\fR for every association
Xthat had \fBCuWlmSampling\fR in the second argument of the association function.
X.LE
X.P
XNote that in the LUT rotation application, we will need at least
X\fBCuWlmEvent()\fR, since we need to be busy rotating the LUTs when
Xcontinuous rotation is True, but we also need to peek now and then to see
Xif anything has happened in the menu.
X.P
XSuppose that when you are using an Association function, you would like
Xthe associated action to occur, but you don't want the \fBCuWlm\fR to be
Xnotified with a \fIWEvent\fR.
XSetting the second argument of the Association function to \fBCuWlmBypass\fR
Xwill accomplish this. (\fBCuWlmBypass\fR and \fBCuWlmSampling\fR may be or'd
Xtogether.)
X.P
XSo, let's put it all together.
XFigure 1 is the complete menu, using widgets contained in the Xcu toolkit.
XFigure 2 is the applicable program fragment from the client application.
XFigure 3 is the equivalent program without using the \fBCuWlm\fR widget.
X.sp
X.ce
XFIGURE 1
X.sp
X.ps -1
XCuWlm {
X.br
X	CuTbl {
X.br
X		formatString "padding(10);\\nc\\nc\\nc."
X.br
X		include "page_widgets"
X.br
X		include "perm_widgets"
X.br
X		}
X.br
X	}
X.sp
X"page_widgets"
X.sp
XCuDeck {
X.br
X	name "pages"
X.br
X	include "rotate_page"
X.br
X	include "modify_page"
X.br
X	}
X.sp
X"modify_page"
X.sp
XCuTbl {
X.br
X	formatString "c\\nc."
X.br
X	name "modification page"
X.br
X	CuBmgr {
X.br
X		name "files"
X.br
X		if setCallback ( String "FILE1"  ==  x )
X.br
X			XtSetValues ( Lbl "FILEX",  label "File1" )
X.br
X		if setCallback ( String "FILE2"  ==  x )
X.br
X			XtSetValues ( Lbl "FILEX",  label "File2" )
X.br
X		if setCallback ( String "FILE3"  ==  x )
X.br
X			XtSetValues ( Lbl "FILEX",  label "File3" )
X.br
X		bmgrType "OneOfMany"
X.br
X		manage "FILE1" "FILE2" "FILE3"
X.br
X		CuTbl {
X.br
X			CuButton { name "FILE1" set "True" }
X.br
X			CuButton { name "FILE2" }
X.br
X			CuButton { name "FILE3" }
X.br
X			}
X.br
X		}
X.br
X	CuBmgr {
X.br
X		name "pos_neg"
X.br
X		bmgrType "SingleToggle"
X.br
X		manage "NEGATIVE"
X.br
X		CuButton { name "NEGATIVE" set "False" }
X.br
X		}
X.br
X	}
X.sp
X"rotate_page"
X.sp
XCuTbl {
X.br
X	name "rotation page"
X.br
X	formatString "c\\nc\\nc\\nc."
X.br
X	CuBmgr {
X.br
X		name "rotation increment"
X.br
X		bmgrType "Transient"
X.br
X		manage "ROTATION INCREMENT"
X.br
X		CuButton { name "ROTATION INCREMENT" }
X.br
X		}
X.br
X	CuBmgr {
X.br
X		name "switch"
X.br
X		bmgrType "DoubleToggle"
X.br
X		manage  "ROTATION ON"  :  Boolean "True"
X.br
X		manage  "ROTATION OFF"  :  Boolean "False"
X.br
X		CuTbl {
X.br
X			CuButton { name "ROTATION ON" }
X.br
X			CuButton { name "ROTATION OFF" set "True" }
X.br
X			}
X.br
X		}
X.br
X	CuBmgr {
X.br
X		name "banks"
X.br
X		bmgrType "AnyOfMany"
X.br
X		manage "RED" : Int "0",  "GRN" : Int "1",  "BLU" : Int "2"
X.br
X		CuTbl {
X.br
X			CuButton { name "RED" }
X.br
X			CuButton { name "GRN" }
X.br
X			CuButton { name "BLU" }
X.br
X			}
X.br
X		}
X.br
X	Lbl { name "FILEX" }  /* current file */
X.br
X	}
X.sp
X"perm_widgets"
X.sp
XCuBmgr {
X.br
X	if setCallback ( String "ROTATION PAGE"  ==  x )
X.br
X		RaiseWidget ( CuDeck "pages",  CuTbl "rotation page" )
X.br
X	if setCallback ( String "MODIFICATION PAGE"  ==  x )
X.br
X		RaiseWidget ( CuDeck "pages",  CuTbl "modification page" )
X.br
X	bmgrType "DoubleToggle"
X.br
X	manage "MODIFICATION PAGE" "ROTATION PAGE"
X.br
X	CuTbl {
X.br
X		CuButton { name "MODIFICATION PAGE" set "True" }
X.br
X		CuButton { name "ROTATION PAGE" }
X.br
X		}
X.br
X	}
X.ps +1
X.sp
X.ce
XFIGURE 2
X.sp
X.ps -1
Xwlm_id = XtCreateManagedWidget ( "wlm", cuWlmWidgetClass, top, wlm_args, ONE ) ;
X.br
XCuWlmAddCallback ( wlm_id, NULL, "CuBmgr", "rotation increment", "setCallback",
Xincrement, NULL ) ;
X.br
XCuWlmAddCallback ( wlm_id, CuWlmSampling, "CuBmgr", "files", "setCallback",
Xfile_read, NULL ) ;
X.br
XCuWlmAddCallback ( wlm_id, CuWlmSampling, "CuBmgr", "banks", "setCallback",
Xbank_mod, True ) ;
X.br
XCuWlmAddCallback ( wlm_id, CuWlmSampling, "CuBmgr", "banks", "unsetCallback",
Xbank_mod, False ) ;
X.br
XCuWlmAddCallback ( wlm_id, CuWlmSampling, "CuBmgr", "pos_neg", "setCallback",
Xpos_neg, True ) ;
X.br
XCuWlmAddCallback ( wlm_id, CuWlmSampling, "CuBmgr", "pos_neg", "unsetCallback",
Xpos_neg, False ) ;
X.br
XCuWlmGetBoolean ( wlm_id, CuWlmSampling, "CuBmgr", "switch", "setCallback",
X&on_switch ) ;
X.sp
XCuWlmSample ( wlm_id )
X.sp
Xwhile (1) {
X.br
X	while (on_switch) {
X.br
X		CuWlmEvent ( wlm_id ) ;
X.br
X		increment () ;
X.br
X		}
X.br
X	CuWlmRequest ( wlm_id ) ;
X.br
X	}
X.ps +1
X.sp
X.ce
XFIGURE 3
X.sp
X.ps -1
X#include "CuTbl.h"
X.br
X#include "CuBmgr.h"
X.br
X#include "CuBmgrR.h"
X.br
X#include "CuLabel.h"
X.br
X#include "CuDeck.h"
X.br
X#include "CuButton.h"
X.sp
XWidget top_deck, outer_tbl, pages_deck, rotation_page, incr_button, incr_bmgr,
X.br
X       switch_tbl, on_button, off_button, switch_bmgr, bank_tbl, red_button,
X.br
X       grn_button, blu_button, bank_bmgr, file_label, modification_page,
X.br
X       files_tbl, file1_button, file2_button, file3_button, files_bmgr,
X.br
X       negative_button, negative_bmgr, permanent_tbl, modpage_button,
X.br
X       rotpage_button, permanent_bmgr ;
X.sp
XArg arg ;
X.br
XWidget managed_buttons[3] ;
X.br
Xcaddr_t managed_values[3] ;
X.sp
Xtop_deck = XtCreateManagedWidget ( "top deck", cuDeckWidgetClass, top, NULL, NULL ) ;
X.br
X	XtSetArg ( arg, XtNformatString, "padding(6);\\nc\\nc\\nc." ) ;
X.br
X	outer_tbl = XtCreateManagedWidget ( "outer_tbl", cuTblWidgetClass, top_deck, &arg, ONE ) ;
X.br
X		pages_deck = XtCreateManagedWidget ( "pages_deck", cuDeckWidgetClass, outer_tbl, NULL, NULL ) ;
X.br
X		XtSetArg ( arg, XtNformatString, "\\nc\\nc\\nc\\nc." ) ;
X.br
X		rotation_page = XtCreateManagedWidget ( "rotation_page", cuTblWidgetClass, pages_deck, &arg, ONE ) ;
X.br
X			incr_button = XtCreateManagedWidget ( "ROTATION INCREMENT", cuButtonWidgetClass, rotation_page, NULL, NULL ) ;
X.br
X				XtSetArg ( arg, XtNbmgrType, CuBmgrTransient ) ;
X.br
X				incr_bmgr = XtCreateManagedWidget ( "incr bmgr", cuBmgrWidgetClass, top_deck, &arg, ONE ) ;
X.br
X				managed_buttons[0] = incr_button ;
X.br
X				managed_values[0] = (caddr_t) "ROTATION INCREMENT" ;
X.br
X				CuBmgrManage (incr_bmgr, managed_buttons, managed_values, ONE ) ;
X.br
X			switch_tbl = XtCreateManagedWidget ( "switch tbl", cuTblWidgetClass, rotation_page, NULL, NULL ) ;
X.br
X				on_button = XtCreateManagedWidget ( "ROTATION ON", cuButtonWidgetClass, switch_tbl, NULL, NULL ) ;
X.br
X				XtSetArg ( arg, XtNset, True ) ;
X.br
X				off_button = XtCreateManagedWidget ( "ROTATION OFF", cuButtonWidgetClass, switch_tbl, NULL, NULL ) ;
X.br
X					XtSetArg ( arg, XtNbmgrType, CuBmgrDoubleToggle ) ;
X.br
X					switch_bmgr = XtCreateManagedWidget ( "switch bmgr", cuBmgrWidgetClass, top_deck, &arg, ONE ) ;
X.br
X					managed_buttons[0] = on_button ;
X.br
X					managed_values[0] = (caddr_t) True ;
X.br
X					managed_buttons[1] = off_button ;
X.br
X					managed_values[1] = (caddr_t) False ;
X.br
X					CuBmgrManage (switch_bmgr, managed_buttons, managed_values, TWO ) ;
X.br
X			bank_tbl = XtCreateManagedWidget ( "bank tbl", cuTblWidgetClass, rotation_page, NULL, NULL ) ;
X.br
X				red_button = XtCreateManagedWidget ( "RED", cuButtonWidgetClass, bank_tbl, NULL, NULL ) ;
X.br
X				grn_button = XtCreateManagedWidget ( "GRN", cuButtonWidgetClass, bank_tbl, NULL, NULL ) ;
X.br
X				blu_button = XtCreateManagedWidget ( "BLU", cuButtonWidgetClass, bank_tbl, NULL, NULL ) ;
X.br
X					XtSetArg ( arg, XtNbmgrType, CuBmgrAnyOfMany ) ;
X.br
X					bank_bmgr = XtCreateManagedWidget ( "bank bmgr", cuBmgrWidgetClass, top_deck, &arg, ONE ) ;
X.br
X					managed_buttons[0] = red_button ;
X.br
X					managed_values[0] = (caddr_t) 0 ;
X.br
X					managed_buttons[1] = grn_button ;
X.br
X					managed_values[1] = (caddr_t) 1 ;
X.br
X					managed_buttons[2] = blu_button ;
X.br
X					managed_values[2] = (caddr_t) 2 ;
X.br
X					CuBmgrManage (bank_bmgr, managed_buttons, managed_values, THREE ) ;
X.br
X			XtSetArg ( arg, XtNlabel, "File1" ) ; 
X.br
X			file_label = XtCreateManagedWidget ( "FILEX", lblWidgetClass, rotation_page, NULL, NULL ) ;
X.br
X		XtSetArg ( arg, XtNformatString, "c\\nc." ) ;
X.br
X		modification_page = XtCreateManagedWidget ( "modification page", cuTblWidgetClass, pages_deck, &arg, ONE ) ;
X.br
X			files_tbl = XtCreateManagedWidget ( "files tbl", cuTblWidgetClass, modification_page, NULL, NULL ) ;
X.br
X				XtSetArg ( arg, XtNset, True ) ;
X.br
X				file1_button = XtCreateManagedWidget ( "FILE1", cuButtonWidgetClass, files_tbl, NULL, NULL ) ;
X.br
X				file2_button = XtCreateManagedWidget ( "FILE2", cuButtonWidgetClass, files_tbl, NULL, NULL ) ;
X.br
X				file3_button = XtCreateManagedWidget ( "FILE3", cuButtonWidgetClass, files_tbl, NULL, NULL ) ;
X.br
X					XtSetArg ( arg, XtNbmgrType, CuBmgrOneOfMany ) ;
X.br
X					files_bmgr = XtCreateManagedWidget ( "files bmgr", cuBmgrWidgetClass, top_deck, &arg, ONE ) ;
X.br
X					managed_buttons[0] = file1_button ;
X.br
X					managed_values[0] = (caddr_t) "FILE1" ;
X.br
X					managed_buttons[1] = file2_button ;
X.br
X					managed_values[1] = (caddr_t) "FILE2" ;
X.br
X					managed_buttons[2] = file3_button ;
X.br
X					managed_values[2] = (caddr_t) "FILE3" ;
X.br
X					CuBmgrManage (files_bmgr, managed_buttons, managed_values, THREE ) ;
X.br
X			negative_button = XtCreateManagedWidget ( "NEGATIVE", cuButtonWidgetClass, modification_page, NULL, NULL ) ;
X.br
X				XtSetArg ( arg, XtNbmgrType, CuBmgrSingleToggle ) ;
X.br
X				negative_bmgr = XtCreateManagedWidget ( "negative bmgr", cuBmgrWidgetClass, top_deck, &arg, ONE ) ;
X.br
X				managed_buttons[0] = negative_button ;
X.br
X				managed_values[0] = (caddr_t) "NEGATIVE" ;
X.br
X				CuBmgrManage ( negative_bmgr, managed_buttons, managed_values, ONE ) ;
X.br
X		permanent_tbl = XtCreateManagedWidget ( "permanent", cuTblWidgetClass, outer_tbl, NULL, NULL ) ;
X.br
X			modpage_button = XtCreateManagedWidget ( "MODIFICATION PAGE", cuButtonWidgetClass, permanent_tbl, NULL, NULL ) ;
X.br
X			XtSetArg ( arg, XtNset, True ) ;
X.br
X			rotpage_button = XtCreateManagedWidget ( "ROTATION PAGE", cuButtonWidgetClass, permanent_tbl, NULL, NULL ) ;
X.br
X				XtSetArg ( arg, XtNbmgrType, CuBmgrDoubleToggle ) ;
X.br
X				permanent_bmgr = XtCreateManagedWidget ( "permanent bmgr", cuBmgrWidgetClass, top_deck, &arg, ONE ) ;
X.br
X				managed_buttons[0] = modpage_button ;
X.br
X				managed_values[0] = (caddr_t) "MODIFICATION PAGE" ;
X.br
X				managed_buttons[1] = rotpage_button ;
X.br
X				managed_values[1] = (caddr_t) "ROTATION PAGE" ;
X.br
X				CuBmgrManage (files_bmgr, managed_buttons, managed_values, TWO ) ;
X
XXtAddCallback (permanent_bmgr, XtNsetCallback, page_changer, NULL ) ;
X.br
XXtAddCallback (files_bmgr, XtNsetCallback, label_changer, NULL ) ;
X.br
XXtAddCallback (switch_bmgr, XtNsetCallback, switch_changer, NULL ) ;
X.br
X ...
X.br
Xstatic void
X.br
Xlabel_changer ( w, client, call )
X.br
X    Widget w ;
X.br
X    caddr_t client ;
X.br
X    caddr_t call ;
X.br
X{
X.br
XArg arg ;
X.br
Xif (strcmp("FILE1", (String) call) == 0) {
X.br
X    XtSetArg ( arg, XtNlabel, "File1" ) ;
X.br
X    XtSetValues ( file_label, &arg, ONE ) ;
X.br
X    }
X.br
Xelse if (strcmp("FILE2", (String) call) == 0) {
X.br
X    XtSetArg ( arg, XtNlabel, "File2" ) ;
X.br
X    XtSetValues ( file_label, &arg, ONE ) ;
X.br
X    }
X.br
Xelse if (strcmp("FILE3", (String) call) == 0) {
X.br
X    XtSetArg ( arg, XtNlabel, "File3" ) ;
X.br
X    XtSetValues ( file_label, &arg, ONE ) ;
X.br
X    }
X.br
Xreturn ;
X.br
X}
X.br
X.sp
Xstatic void
X.br
Xpage_changer ( w, client, call )
X.br
X    Widget w ;
X.br
X    caddr_t client ;
X.br
X    caddr_t call ;
X.br
X{
X.br
Xif (strcmp("MODIFICATION PAGE", (String) call) == 0)
X.br
X    RaiseWidget (pages_deck, modification_page ) ;
X.br
Xelse
X.br
X    RaiseWidget (pages_deck, rotation_page ) ;
X.br
X}
X.sp
Xstatic void
X.br
Xswitch_changer (w, client, call )
X.br
X    Widget w ;
X.br
X    caddr_t client ;
X.br
X    caddr_t call ;
X.br
X{
X.br
Xon_switch = (Boolean) call ;
X.br
X}
X.ps +1
X.sp
XI could rest my case here, I think.
XThe code without the \fBCuWlm\fR is significantly longer, and to figure out
Xwhat it does without a lot of comments is next to impossible, whereas the
XWLDL is compact and much more intelligible.
Xbut perhaps the best is yet to come.
XConsider the implications of making a slight change in the menu.
XWithout the \fBCuWlm\fR, the application source code would have to be edited,
Xrecompiled, and relinked.
XWith the \fBCuWlm\fR, only the WLDL needs to be edited.
XThis convenience enables very rapid prototyping of menus.
X

END_OF_FILE
echo shar: NEWLINE appended to \"'doc/wlm_tutor.mm'\"
if test 22936 -ne `wc -c <'doc/wlm_tutor.mm'`; then
    echo shar: \"'doc/wlm_tutor.mm'\" unpacked with wrong size!
fi
# end of 'doc/wlm_tutor.mm'
fi
if test -f 'src/CuCommandI.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/CuCommandI.h'\"
else
echo shar: Extracting \"'src/CuCommandI.h'\" \(2616 characters\)
sed "s/^X//" >'src/CuCommandI.h' <<'END_OF_FILE'
X/*
X *
X *  A few definitions to make CuCommand.c easier to read.
X *   
X */
X
X  /* Yes, this is gross, but the code will be easier to read.
X     Trust me.  */
X#define ComWx                            cbw->core.x
X#define ComWy                            cbw->core.y
X#define ComWdepth                        cbw->core.depth
X#define ComWwidth                        cbw->core.width
X#define ComWheight                       cbw->core.height
X#define ComWborder_width                 cbw->core.border_width
X#define ComWbackground                   cbw->core.background_pixel
X#define ComWforeground                   cbw->label.foreground
X#define ComWfont                         cbw->label.font
X#define ComWlabel                        cbw->label.label
X#define ComWjustify                      cbw->label.justify
X#define ComWinternalWidth                cbw->label.internal_width
X#define ComWinternalHeight               cbw->label.internal_height
X#define ComWlabelX                       cbw->label.label_x
X#define ComWlabelY                       cbw->label.label_y
X#define ComWlabelWidth                   cbw->label.label_width
X#define ComWlabelHeight                  cbw->label.label_height
X#define ComWlabelLen                     cbw->label.label_len
X#define ComWgrayPixmap                   cbw->label.gray_pixmap
X#define ComWsensitive                    cbw->core.sensitive 
X#define ComWnormalGC                     cbw->command.normal_GC
X#define ComWgrayGC                       cbw->command.gray_GC
X#define ComWcallbackList                 cbw->command.callback_list
X#define ComWcallback                     cbw->command.callback
X#define ComWclosure                      cbw->command.closure
X#define ComWhighlightGC                  cbw->command.highlight_GC
X#define ComWinverseGC                    cbw->command.inverse_GC
X#define ComWinverseTextGC                cbw->command.inverse_text_GC
X#define ComWhighlightThickness           cbw->command.highlight_thickness
X#define ComWset                          cbw->command.set
X#define ComWdisplaySet                   cbw->command.display_set
X#define ComWdisplayHighlighted           cbw->command.display_highlighted
X#define ComWhighlighted                  cbw->simple.highlighted
X
X#define XtCBField(cbw,field)  cbw->command.field
X#define XtLField(cbw,field)   cbw->label.field
X#define XtCField(cbw,field)   cbw->core.field
X
X
Xstatic void Initialize();
Xstatic void Redisplay();
Xstatic Boolean SetValues();
Xstatic void Set();
Xstatic void Notify();
Xstatic void Unset();
Xstatic void Highlight();
Xstatic void Unhighlight();
Xstatic void Unset();
Xstatic void Destroy();

END_OF_FILE
echo shar: NEWLINE appended to \"'src/CuCommandI.h'\"
if test 2617 -ne `wc -c <'src/CuCommandI.h'`; then
    echo shar: \"'src/CuCommandI.h'\" unpacked with wrong size!
fi
# end of 'src/CuCommandI.h'
fi
if test -f 'src/CuLabel.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/CuLabel.c'\"
else
echo shar: Extracting \"'src/CuLabel.c'\" \(26542 characters\)
sed "s/^X//" >'src/CuLabel.c' <<'END_OF_FILE'
X#include "disclaimer.h"
X
X/*
X * CuLabel.c - CuLabel widget
X */
X
X#define XtStrlen(s)		((s) ? strlen(s) : 0)
X#define IsSensitive(w) ((w)->core.sensitive && (w)->core.ancestor_sensitive)
X
X#include <ctype.h>
X#include <X11/IntrinsicP.h>
X#include <X11/Xos.h>
X#include <X11/StringDefs.h>
X#include "CuLabelP.h"
X#include "CuSimpleP.h"
X#include "CuJustifyR.h"
X#include "CuGravityR.h"
X#include "CuFloatR.h"
X
Xvoid Cu_copy_ds () ;
X
X/*
X * Full class record constant
X */
X
X/* Private Data */
X
X/*
X * XtResource :
X *	name, class, type, size,
X *	offset, default_type, default_address
X *
X * These are the resources needed in addition to core resources
X */
X
Xstatic CuGravity	def_gravity = CuCenterGravity ;
Xstatic CuJustify	defJustify = CuJustifyCenter ;
Xstatic float		defLFactor = 1.0 ;
Xstatic Dimension	defIHeight = 2 ;
Xstatic Dimension	defIWidth = 2 ;
X
X#define offset(field) XtOffset(CuLabelWidget, field)
X
Xstatic XtResource resources[] =
X    {
X     {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
X	offset(label.foreground), XtRString, "Black"}
X    ,{XtNfont,  XtCFont, XtRFontStruct, sizeof(XFontStruct *),
X	offset(label.font),XtRString, "Fixed"}
X    ,{XtNlabel,  XtCLabel, XtRString, sizeof(String),
X	offset(label.label), XtRString, NULL}
X    ,{XtNbiggestLabel,  XtCLabel, XtRString, sizeof(String),
X	offset(label.big_label), XtRString, NULL}
X    ,{XtNjustify, XtCJustify, XtRJustify, sizeof(CuJustify),
X	offset(label.justify), XtRJustify, (caddr_t)&defJustify}
X    ,{XtNinternalWidth, XtCWidth, XtRDimension,  sizeof(Dimension),
X	offset(label.internal_width), XtRDimension, (caddr_t)&defIWidth}
X    ,{XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
X	offset(label.internal_height), XtRDimension, (caddr_t)&defIHeight}
X    ,{XtNlineFactor, XtCLineFactor, XtRFloat, sizeof(float),
X	offset(label.line_factor), XtRFloat, (caddr_t)&defLFactor}
X    ,{XtNgravity, XtCGravity, XtRGravity, sizeof(CuGravity),
X	offset(label.gravity), XtRGravity, (caddr_t)&def_gravity}
X    ,{XtNbitmap, XtCPixmap, XtRPixmap, sizeof(Pixmap),
X	offset(label.pixmap), XtRPixmap, (caddr_t)None}
X    } ;
X
Xstatic void ClassInitialize() ;
Xstatic void ClassPartInitialize();
Xstatic void Initialize() ;
Xstatic void Resize() ;
Xstatic void Redisplay() ;
Xstatic void RedisplayText() ;
Xstatic void Destroy() ;
Xstatic Boolean SetValues() ;
Xstatic XtGeometryResult QueryGeometry() ;
Xstatic void find_newlines () ;
Xstatic void SetTextWidthAndHeight () ;
Xstatic void GetSensitiveTextGC () ;
Xstatic void GetInsensitiveTextGC () ;
Xstatic void GetBackgroundGC () ;
Xstatic Dimension PreferredWidth () ;
Xstatic Dimension PreferredHeight () ;
X
X#define superclass (&cuSimpleClassRec)
X
XCuLabelClassRec cuLabelClassRec =
X{
X  {
X  /* core_class fields */	
X    /* superclass	  	*/	(WidgetClass) &cuSimpleClassRec,
X    /* class_name	  	*/	"CuLabel",
X    /* widget_size	  	*/	sizeof(CuLabelRec),
X    /* class_initialize   	*/	ClassInitialize,
X    /* class_part_initialize	*/	ClassPartInitialize,
X    /* class_inited       	*/	FALSE,
X    /* initialize	  	*/	Initialize,
X    /* initialize_hook		*/	NULL,
X    /* realize		  	*/	XtInheritRealize,
X    /* actions		  	*/	NULL,
X    /* num_actions	  	*/	0,
X    /* resources	  	*/	resources,
X    /* num_resources	  	*/	XtNumber(resources),
X    /* xrm_class	  	*/	NULLQUARK,
X    /* compress_motion	  	*/	TRUE,
X    /* compress_exposure  	*/	TRUE,
X    /* compress_enterleave	*/	TRUE,
X    /* visible_interest	  	*/	FALSE,
X    /* destroy		  	*/	Destroy,
X    /* resize		  	*/	Resize,
X    /* expose		  	*/	Redisplay,
X    /* set_values	  	*/	SetValues,
X    /* set_values_hook		*/	NULL,
X    /* set_values_almost	*/	XtInheritSetValuesAlmost,
X    /* get_values_hook		*/	NULL,
X    /* accept_focus	 	*/	NULL,
X    /* version			*/	XtVersion,
X    /* callback_private   	*/	NULL,
X    /* tm_table		   	*/	NULL,
X    /* query_geometry		*/	QueryGeometry,
X    /* display_accelerator	*/	XtInheritDisplayAccelerator,
X    /* extension		*/	NULL,
X  },
X  {
X    XtInheritChangeSensitive, /* Simple Class fields */
X    XtInheritDrawFacets,
X    XtInheritDrawHighlight
X  },
X  {
X    RedisplayText,                        /* CuLabel Class fields  */
X  },
X} ;
X
X/* For use by clients... */
XWidgetClass cuLabelWidgetClass = (WidgetClass) &cuLabelClassRec ;
X
X/**
X ***
X **** Toolkit Procedures
X ***
X **/
X
X/***** **** *** ** * ClassInitialize * ** *** **** *****/
X
Xstatic void
XClassInitialize()
X{
XCuAddStringToJustifyConverter () ;
XCuAddStringToGravityConverter () ;
XCuAddStringToFloatConverter () ;
X
Xreturn ;
X}
X
X/***** **** *** ** * ClassPartInitialize * ** *** **** *****/
X
Xstatic void
XClassPartInitialize(class)
X    WidgetClass class;
X{
Xregister CuLabelWidgetClass c = (CuLabelWidgetClass)class;
X
Xif (c->label_class.redisplay_text == XtInheritRedisplayText)
X    c->label_class.redisplay_text = RedisplayText;
X
Xreturn ;
X}
X
X/***** **** *** ** * Initialize * ** *** **** *****/
X
Xstatic void
XInitialize (request, new)
X    Widget request, new ;
X{
XCuLabelWidget lw = (CuLabelWidget) new ;
XDimension explicit_width = request->core.width ;
XDimension explicit_height = request->core.height ;
XDimension facet_add = (lw->simple.shadow ? 1 : 2) * lw->simple.facet_width ;
XDimension preferred_width, preferred_height ;
X
Xif (lw->label.label == NULL) 
X    lw->label.label = lw->core.name ;
Xelse
X    Cu_copy_ds (&lw->label.label, lw->label.label) ;
X
Xif (lw->label.big_label != NULL) 
X    Cu_copy_ds (&lw->label.big_label, lw->label.big_label) ;
X
XGetSensitiveTextGC (lw, lw->label.foreground) ;
XGetInsensitiveTextGC (lw, lw->label.foreground) ;
Xif (lw->simple.shadow)
X    GetBackgroundGC (lw, lw->simple.background_pixel) ;
Xelse
X    GetBackgroundGC (lw, lw->core.background_pixel) ;
Xlw->label.needs_fill = True ;
X
Xlw->label.x = NULL ;
Xlw->label.y = NULL ;
Xlw->label.line_width = NULL ;
Xlw->label.len = NULL ;
X
Xif (lw->label.big_label)
X    {
X    find_newlines (lw->label.big_label, &lw->label.locations, &lw->label.n_lines) ;
X    SetTextWidthAndHeight (lw, lw->label.big_label) ;
X
X    if (lw->core.width == 0)
X	{
X        lw->core.width = lw->label.total_width + 2*lw->label.internal_width +
X						 facet_add ;
X	}
X    if (lw->core.height == 0)
X	{
X        lw->core.height = lw->label.total_height +
X			  2*lw->label.internal_height +
X			  facet_add ;
X
X	}
X    lw->label.big_width = lw->core.width ;
X    lw->label.big_height = lw->core.height ;
X    }
X
Xfind_newlines (lw->label.label, &lw->label.locations, &lw->label.n_lines) ;
XSetTextWidthAndHeight (lw, lw->label.label) ;
Xif (!lw->label.big_label)
X    {
X    if (lw->core.width == 0)
X	{
X	lw->core.width = lw->label.total_width + 2*lw->label.internal_width +
X						 facet_add ;
X	}
X    if (lw->core.height == 0)
X	{
X	lw->core.height = lw->label.total_height + 2*lw->label.internal_height+
X						   facet_add ;
X	}
X    }
X
X/*
X * if width or height was explicitly set for this label and it is greater
X * than the preferred dimensions, then set big_label to them. 
X */
X
Xpreferred_width = PreferredWidth(lw) ;
Xpreferred_height = PreferredHeight(lw) ;
Xif (!lw->label.big_label &&
X    (explicit_width > preferred_width || (explicit_height > preferred_height))
X   )
X    {
X    lw->label.big_label = (String) 1 ;
X    lw->label.big_width = (explicit_width > preferred_width) ?
X			    explicit_width : preferred_width ;
X    lw->label.big_height = (explicit_height > preferred_height) ?
X			    explicit_height : preferred_height ;
X    }
X/**
Xlw->label.old_width = lw->core.width; 
Xlw->label.old_height = lw->core.height; 
X**/
X(*XtClass(new)->core_class.resize) (new) ;
X
Xreturn ;
X}
X
X/***** **** *** ** * Resize * ** *** **** *****/
X
Xstatic void
XResize (w)
X    Widget w ;
X{
Xint i ;
XCuLabelWidget lw = (CuLabelWidget) w ;
XDimension preferred_width = PreferredWidth(lw) ;
XDimension preferred_height = PreferredHeight(lw) ;
XDimension facet_add = lw->simple.shadow ? 0 : 3 ;
XDimension facet_divisor = lw->simple.shadow ? 1 : 2 ;
X
Xif (lw->core.width < preferred_width)
X    {
X    /* Since we have to get smaller, we'll kill the frills... */
X    /* First reduce the internal padding */
X    /* If the squeeze is still on, kill the facet */
X    /* If the squeeze is still on, there's nothing left but text, and
X       I don't think I should mess with it */
X    Dimension delta, original_delta ;
X
X    delta = (preferred_width - lw->core.width + facet_add) / facet_divisor ;
X    original_delta = delta ;
X    if (delta > lw->label.internal_width)
X	delta = lw->label.internal_width; 
X    lw->label.internal_width -= delta ;
X
X    delta = original_delta - delta ;
X    if (delta > lw->simple.facet_width)
X	delta = lw->simple.facet_width; 
X    lw->simple.facet_width -= delta ;
X    }
X
Xif (lw->core.height < preferred_height)
X    {
X    /* same as for width */
X    Dimension delta, original_delta ;
X
X    delta = (preferred_height - lw->core.height + facet_add) / facet_divisor ;
X    original_delta = delta ;
X    if (delta > lw->label.internal_height)
X	delta = lw->label.internal_height; 
X    lw->label.internal_height -= delta ;
X
X    delta = original_delta - delta ;
X    if (delta > lw->simple.facet_width)
X	delta = lw->simple.facet_width; 
X    lw->simple.facet_width -= delta ;
X    }
X
Xfor (i=0;  i < lw->label.n_lines;  i++)
X    {
X    switch (lw->label.justify)
X      {
X	case CuJustifyLeft   :
X	    lw->label.x[i] = 0 ;
X	    break ;
X
X	case CuJustifyRight  :
X	    lw->label.x[i] = lw->label.total_width - lw->label.line_width[i] ;
X	    break ;
X
X	case CuJustifyCenter :
X	    lw->label.x[i] = (lw->label.total_width -
X			      lw->label.line_width[i]) / 2 ;
X	    break ;
X      }
X    switch (lw->label.gravity)
X	{
X	case CuWestGravity :
X	case CuNorthWestGravity :
X	case CuSouthWestGravity :
X	    if (lw->simple.shadow)
X		lw->label.x[i] += lw->label.internal_width +
X				  lw->simple.facet_width ;
X	    else
X		lw->label.x[i] += lw->label.internal_width ;
X	    break ;
X	case CuEastGravity :
X	case CuNorthEastGravity :
X	case CuSouthEastGravity :
X	    lw->label.x[i] += ((int)lw->core.width - lw->label.internal_width -
X			     lw->label.total_width - lw->simple.facet_width) ;
X	    break ;
X	case CuNorthGravity :
X	case CuCenterGravity :
X	case CuSouthGravity :
X	    if (lw->simple.shadow)
X		lw->label.x[i] += ((int)lw->core.width -
X				    lw->label.total_width -
X				    lw->simple.facet_width) / 2 ;
X	    else
X		lw->label.x[i] += ((int)lw->core.width -
X				    lw->label.total_width) / 2 ;
X	    break ;
X	}
X
X    /* to protect against the dreaded unsigned */
X    if (lw->label.x[i] < 0)
X	lw->label.x[i] = 0 ;
X
X    lw->label.y[i] =
X	lw->label.line_height * (i+1) +
X	lw->label.line_height * (lw->label.line_factor - 1.0) * i -
X	lw->label.font->max_bounds.descent ;
X
X    switch (lw->label.gravity)
X	{
X	case CuNorthWestGravity :
X	case CuNorthGravity :
X	case CuNorthEastGravity :
X	    if (lw->simple.shadow)
X		lw->label.y[i] += lw->label.internal_height ;
X	    else
X		lw->label.y[i] += lw->label.internal_height +
X				  lw->simple.facet_width ;
X	    break ;
X
X	case CuWestGravity :
X	case CuCenterGravity :
X	case CuEastGravity :
X	    if (lw->simple.shadow)
X		lw->label.y[i] += ((int)lw->core.height -
X				    lw->label.total_height -
X				    lw->simple.facet_width) / 2 ;
X	    else
X		lw->label.y[i] += ((int)lw->core.height -
X				    lw->label.total_height) / 2 ;
X	    break ;
X
X	case CuSouthWestGravity :
X	case CuSouthGravity :
X	case CuSouthEastGravity :
X	    lw->label.y[i] += (int)lw->core.height - lw->label.total_height -
X				lw->label.internal_height -
X				lw->simple.facet_width ;
X	    break ;
X	}
X    }
X
X/* for invocation of callbacks */
X(*superclass->core_class.resize)( w ) ;
X
Xreturn ;
X}
X
X/***** **** *** ** * SetValues * ** *** **** *****/
X
X/*
X * Set specified arguments into widget
X */
X
X/* ARGSUSED */
Xstatic Boolean
XSetValues (current, request, new)
X    Widget current, request, new ;
X{
XCuLabelWidget curlw = (CuLabelWidget) current ;
XCuLabelWidget newlw = (CuLabelWidget) new ;
XBoolean need_to_redisplay = False ;
XBoolean was_resized = False ;
XDimension facet_add = (newlw->simple.shadow ? 1 : 2)*newlw->simple.facet_width ;
X
Xif (newlw->label.label == NULL)
X    Cu_copy_ds (&newlw->label.label, newlw->core.name) ;
X
Xif (curlw->label.big_label != newlw->label.big_label)
X    {
X    was_resized = True ;
X    }
X
Xnewlw->label.newlines_found = False ;
Xif (curlw->label.label != newlw->label.label)
X    {
X    if (curlw->label.label != curlw->core.name)
X	XtFree( (char *)curlw->label.label ) ;
X
X    if (newlw->label.label != newlw->core.name)
X	Cu_copy_ds (&newlw->label.label, newlw->label.label) ;
X
X    find_newlines (newlw->label.label, &newlw->label.locations, &newlw->label.n_lines) ;
X    newlw->label.newlines_found = True ;
X
X    was_resized = True ;
X    }
X
Xif (curlw->label.line_factor != newlw->label.line_factor)
X    {
X    union {int iii ; float xxx ;} uni ;
X    /*
X     * This seems like a disgusting hack, but it's virtually impossible to
X     * handle floats in resources...
X     */
X    uni.xxx = newlw->label.line_factor ;
X    newlw->label.line_factor = *((float *) uni.iii) ;
X    was_resized = True ;
X    }
X
Xif (
X   was_resized
X   || curlw->label.font != newlw->label.font
X   || curlw->label.internal_height != newlw->label.internal_height
X   || curlw->label.internal_width != newlw->label.internal_width
X   || curlw->label.pixmap != newlw->label.pixmap
X   || curlw->simple.facet_width != newlw->simple.facet_width
X   )
X    {
X    if (newlw->label.big_label != curlw->label.big_label)
X	{
X	find_newlines (newlw->label.big_label, &newlw->label.locations, &newlw->label.n_lines) ;
X	SetTextWidthAndHeight (newlw, newlw->label.big_label) ;
X
X	newlw->core.width = newlw->label.total_width +
X			    2 * newlw->label.internal_width + facet_add ;
X	newlw->core.height = newlw->label.total_height +
X			     2 * newlw->label.internal_height + facet_add ;
X	newlw->label.big_width = newlw->core.width ;
X	newlw->label.big_height = newlw->core.height ;
X	}
X
X    if (!newlw->label.newlines_found)
X	find_newlines (newlw->label.label,
X		       &newlw->label.locations, &newlw->label.n_lines) ;
X    SetTextWidthAndHeight (newlw, newlw->label.label) ;
X    (*XtClass(newlw)->core_class.resize) (new) ;
X    need_to_redisplay = True ;
X    if (newlw->label.big_label == curlw->label.big_label)
X	{
X	newlw->core.width = newlw->label.total_width +
X			    2 * newlw->label.internal_width + facet_add ;
X	newlw->core.height = newlw->label.total_height +
X			    2 * newlw->label.internal_height + facet_add ;
X	}
X    }
Xelse
Xif (
X   curlw->label.justify != newlw->label.justify
X   || curlw->label.gravity != newlw->label.gravity
X   )
X    {
X    if ((int)newlw->label.gravity > 9)
X	newlw->label.gravity = (CuGravity) 9 ; /* KLUDGE! */
X    /* These things don't cause width and height to change */
X    /* But resize does what we need for justification/gravity */
X    (*XtClass(newlw)->core_class.resize) (new) ;
X    need_to_redisplay = True ;
X    }
X
Xif (curlw->core.border_width != newlw->core.border_width)
X    {
X    Mask changes_mask ;
X    XWindowChanges changes ;
X
X    changes_mask = CWBorderWidth ;
X    changes.border_width = newlw->core.border_width ;
X    if (XtIsRealized(current))
X	{
X	XConfigureWindow (XtDisplay(current), XtWindow(current),
X				 changes_mask, &changes) ;
X	}
X    }
X
Xif (curlw->label.foreground != newlw->label.foreground
X    || curlw->label.font->fid != newlw->label.font->fid)
X    {
X    XtDestroyGC (curlw->label.sensitive_text_GC) ;
X    XtDestroyGC (curlw->label.insensitive_text_GC) ;
X    GetSensitiveTextGC (newlw, newlw->label.foreground) ;
X    GetInsensitiveTextGC (newlw, newlw->label.foreground) ;
X    }
X
Xif (curlw->core.background_pixel != newlw->core.background_pixel)
X    {
X    XtDestroyGC (curlw->label.background_GC) ;
X    if (newlw->simple.shadow)
X	GetBackgroundGC (newlw, newlw->simple.background_pixel) ;
X    else
X	GetBackgroundGC (newlw, newlw->core.background_pixel) ;
X    }
X
Xreturn need_to_redisplay ;
X}
X
X/***** **** *** ** * QueryGeometry * ** *** **** *****/
X
Xstatic XtGeometryResult
XQueryGeometry (widget, requested, preferred)
X    Widget widget ;
X    XtWidgetGeometry *requested ;
X    XtWidgetGeometry *preferred ;
X{
X/*
X * Examine bits in requested->request_mode
X * Evaluate preferred geometry of the widget
X * Store the result in preferred, setting bits cared about in request_mode
X *  (CWX, CWY,  CWWidth, CWHeight,  CWBorderWidth,  CWSibling,  CWStackMode)
X *
X * acceptable without modification				XtGeometryYes
X *
X * one field in requested != one field in preferred ||
X * one bit set in preferred that is not set in requested	XtGeometryAlmost
X *
X * if preferred == current					XtGeometryNo
X */
X
XXtGeometryResult return_mode ;
XCuLabelWidget lw = (CuLabelWidget) widget ;
X
Xpreferred->width = PreferredWidth (lw) ;
Xpreferred->height = PreferredHeight (lw); 
Xpreferred->request_mode = (CWWidth | CWHeight) ;
X
Xif ((requested->request_mode & (CWWidth | CWHeight)) == 0)
X    {
X    /* parent isn't interested in anything we're interested in */
X    return XtGeometryNo ;
X    }
X
Xif (
X    (
X     ((requested->request_mode & CWWidth) != 0 &&
X      preferred->width == requested->width)
X		    ||
X     ((requested->request_mode & CWWidth) == 0)
X    )
X		    &&
X    (
X     ((requested->request_mode & CWHeight) != 0 &&
X      preferred->height == requested->height)
X		    ||
X     ((requested->request_mode & CWHeight) == 0)
X    )
X   )
X    {
X    /* Our values already identical to those the parent is interested in */
X    return XtGeometryNo ;
X    }
X
X/*
X * That takes care of the simple cases, now we have to take a closer look...
X * I don't mind getting bigger than the smallest possible size.
X */
X
Xreturn_mode = XtGeometryYes ;
X
Xif (
X    (requested->request_mode & CWHeight) &&
X    (requested->height < preferred->height)
X   )
X    {
X    return_mode = XtGeometryAlmost ;
X    }
Xif (
X    (requested->request_mode & CWWidth) &&
X    (requested->width < preferred->width)
X   )
X    {
X    return_mode = XtGeometryAlmost ;
X    }
X
Xreturn return_mode ;
X}
X
X/***** **** *** ** * Destroy * ** *** **** *****/
X
Xstatic void
XDestroy (widget)
X    Widget widget ;
X{
XCuLabelWidget lw = (CuLabelWidget) widget ;
X
X/*
X * free dynamically allocated data
X */
X
Xif (!XtIsRealized (widget))
X    return ;
X
XXtFree ((char *) lw->label.x) ;
XXtFree ((char *) lw->label.y) ;
XXtFree ((char *) lw->label.len) ;
XXtFree ((char *) lw->label.line_width) ;
XXtFree ((char *) lw->label.label) ;
XXtFree ((char *) lw->label.locations) ;
XXtDestroyGC (lw->label.sensitive_text_GC) ;
XXtDestroyGC (lw->label.insensitive_text_GC) ;
X
Xreturn ;
X}
X
X/***** **** *** ** * Redisplay * ** *** **** *****/
X
Xstatic void Redisplay(w, event, region)
X    Widget w;
X    XEvent *event;		/* unused */
X    Region region;		/* unused */
X{
XCuLabelWidget lw = (CuLabelWidget) w;
XGC	    gc ;
X
X/*
X * Repaint the background if need be
X * Redisplay the text
X * Allow superclass to handle facets and highlights
X */
Xgc = IsSensitive(w) ?
X	lw->label.sensitive_text_GC : lw->label.insensitive_text_GC ;
X
X(*superclass->core_class.expose)( w, event, region ) ;
X
Xif (lw->label.pixmap == None)
X    {
X    if (lw->label.needs_fill)
X	{
X	if (lw->simple.shadow)
X	    {
X	    XFillRectangle(XtDisplay(w),XtWindow(w), lw->label.background_GC,
X		    0, 0,
X		    lw->core.width - lw->simple.facet_width,
X		    lw->core.height - lw->simple.facet_width);
X	    XDrawRectangle(XtDisplay(w),XtWindow(w),
X		    IsSensitive(w) ? lw->label.sensitive_text_GC :
X				     lw->label.insensitive_text_GC,
X		    0, 0,
X		    lw->core.width - lw->simple.facet_width,
X		    lw->core.height - lw->simple.facet_width);
X	    }
X	else
X	    {
X	    XFillRectangle(XtDisplay(w),XtWindow(w), lw->label.background_GC,
X		    lw->simple.facet_width, lw->simple.facet_width,
X		    lw->core.width - 2*lw->simple.facet_width,
X		    lw->core.height - 2*lw->simple.facet_width);
X	    }
X	}
X    else
X    if (lw->simple.shadow)
X	{
X	XDrawRectangle(XtDisplay(w),XtWindow(w),
X		IsSensitive(w) ? lw->label.sensitive_text_GC :
X				 lw->label.insensitive_text_GC,
X		0, 0,
X		lw->core.width - lw->simple.facet_width,
X		lw->core.height - lw->simple.facet_width);
X	}
X    (*((CuLabelWidgetClass)XtClass(w))->label_class.redisplay_text)
X	(w, event, region) ;
X    }
Xelse if (lw->label.depth == 1)
X   { /* depth */
X   if (lw->simple.shadow)
X       XCopyPlane(
X	      XtDisplay(w), lw->label.pixmap, XtWindow(w), gc,
X		0, 0,
X	      lw->label.total_width, lw->label.total_height,
X	      lw->label.internal_width,
X	      lw->label.internal_height, 1L);
X   else
X       XCopyPlane(
X	      XtDisplay(w), lw->label.pixmap, XtWindow(w), gc,
X		0,0,
X	      lw->label.total_width, lw->label.total_height,
X	      lw->label.internal_width + lw->simple.facet_width,
X	      lw->label.internal_height + lw->simple.facet_width, 1L);
X   }
Xelse
X   {
X   if (lw->simple.shadow)
X       XCopyArea(
X	     XtDisplay(w), lw->label.pixmap, XtWindow(w), gc,
X		0,0,
X	      lw->label.total_width, lw->label.total_height,
X	      lw->label.internal_width,
X	      lw->label.internal_height,
X	      lw->label.depth);
X   else
X       XCopyArea(
X	     XtDisplay(w), lw->label.pixmap, XtWindow(w), gc,
X		0,0,
X	      lw->label.total_width, lw->label.total_height,
X	      lw->label.internal_width + lw->simple.facet_width,
X	      lw->label.internal_height + lw->simple.facet_width,
X	      lw->label.depth);
X   }
X
Xreturn ;
X}
X
X/**
X ***
X **** Private Procedures
X ***
X **/
X
X/***** **** *** ** * RedisplayText * ** *** **** *****/
X
X/*
X * Repaint the widget window
X */
X
Xstatic void
XRedisplayText (w, event, region)
X    Widget w ;
X    XEvent *event ;
X    Region region ;
X{
Xint i ;
XCuLabelWidget lw = (CuLabelWidget) w ;
X
Xfor (i=0;  i < lw->label.n_lines;  i++)
X    {
X    XDrawString
X	(
X	XtDisplay(w), XtWindow(w),
X	IsSensitive(w) ?
X		lw->label.sensitive_text_GC : lw->label.insensitive_text_GC,
X	lw->label.x[i], lw->label.y[i],
X	&lw->label.label[lw->label.locations[i]], (int) lw->label.len[i]
X	) ;
X    }
Xreturn ;
X}
X
X/***** **** *** ** * SetTextWidthAndHeight * ** *** **** *****/
X
X/*
X * Calculate width and height of displayed text in pixels
X */
X
Xstatic void
XSetTextWidthAndHeight (lw, text)
X    CuLabelWidget lw ;
X    String text ;
X{
X#define lwl	lw->label
X
Xint i ;
Xregister XFontStruct	*fs = lwl.font ;
X
X/*
X * allocate space for arrays of x, y, and len
X */
X
Xif (lw->label.pixmap != None) {
X    Window root;
X    int x, y;
X    unsigned int width, height, bw, depth;
X    if (XGetGeometry(XtDisplay(lw), lw->label.pixmap, &root, &x, &y,
X		     &width, &height, &bw, &depth)) {
X	lw->label.total_height = height;
X	lw->label.total_width = width;
X	lw->label.depth = depth;
X	return;
X    }
X}
X
Xif (XtIsRealized ((Widget)lw))
X    {
X    if (lwl.x) XtFree ((char *) lwl.x) ;
X    if (lwl.y) XtFree ((char *) lwl.y) ;
X    if (lwl.len) XtFree ((char *) lwl.len) ;
X    if (lwl.line_width) XtFree ((char *) lwl.line_width) ;
X    }
X
Xlwl.x = (Position *) XtMalloc (lwl.n_lines * sizeof (Position)) ;
Xlwl.y = (Position *) XtMalloc (lwl.n_lines * sizeof (Position)) ;
Xlwl.len = (unsigned int *) XtMalloc (lwl.n_lines * sizeof (unsigned int)) ;
Xlwl.line_width = (int *) XtMalloc (lwl.n_lines * sizeof (int)) ;
X
X/*
X * Now to find the width and height of the entire label
X * The height is (sum of line heights + sum of interline spacings)
X * The width is max (line widths)
X */
X
Xlwl.line_height = fs->max_bounds.ascent + fs->max_bounds.descent ;
Xlwl.total_height = lwl.line_height * lwl.n_lines +
X		   lwl.line_height * (lwl.line_factor - 1.0) *
X		   (lwl.n_lines - 1) ;
X
Xlwl.total_width = 0 ;
Xfor (i=0;  i < lwl.n_lines;  i++)
X    {
X    lwl.len[i] = XtStrlen(&text[lwl.locations[i]]) ;
X    lwl.line_width[i] = XTextWidth(fs, &text[lwl.locations[i]], lwl.len[i]) ;
X    if (lwl.total_width < lwl.line_width[i])
X	lwl.total_width = lwl.line_width[i] ;
X    }
X
Xreturn ;
X}
X
X/***** **** *** ** * GetInsensitiveTextGC * ** *** **** *****/
X
Xstatic void
XGetInsensitiveTextGC(lw, foreground_color)
X    CuLabelWidget lw;
X    Pixel foreground_color ;
X{
XXGCValues	values;
X
Xvalues.foreground = foreground_color ;
Xvalues.font	  = lw->label.font->fid ;
Xvalues.tile       = XmuCreateStippledPixmap (XtScreen((Widget)lw),
X					     lw->label.foreground,
X					     lw->core.background_pixel,
X					     lw->core.depth) ;
Xvalues.fill_style = FillTiled ;
X
Xlw->label.insensitive_text_GC = XtGetGC(
X    (Widget)lw, 
X    (unsigned) GCForeground | GCFont | GCTile | GCFillStyle, 
X    &values);
Xreturn ;
X}
X
X/***** **** *** ** * GetSensitiveTextGC * ** *** **** *****/
X
Xstatic void
XGetSensitiveTextGC (lw, foreground_color)
X    CuLabelWidget lw ;
X    Pixel foreground_color ;
X{
XXGCValues	values ;
X
Xvalues.foreground	= foreground_color ;
Xvalues.font		= lw->label.font->fid ;
X
Xlw->label.sensitive_text_GC = XtGetGC(
X    (Widget)lw,
X    (unsigned) GCForeground | GCFont,
X    &values) ;
Xreturn ;
X}
X
X/***** **** *** ** * GetBackgroundGC * ** *** **** *****/
X
Xstatic void
XGetBackgroundGC (lw, background_color)
X    CuLabelWidget lw ;
X    Pixel background_color ;
X{
XXGCValues	values ;
X
Xvalues.foreground	= background_color ;
X
Xlw->label.background_GC = XtGetGC(
X    (Widget)lw,
X    (unsigned) GCForeground,
X    &values) ;
Xreturn ;
X}
X
X/***** **** *** ** * find_newlines * ** *** **** *****/
X
X#define FIND_NEWLINES_MAX_LINES	100
X
Xstatic void
Xfind_newlines (text, line_locations, n_lines)
X    char *text ;
X    unsigned int **line_locations ;
X    unsigned int *n_lines ;
X{
Xint string_length ;
Xint loc[FIND_NEWLINES_MAX_LINES] ;	/* local version of line_locations */
Xint n = 0 ;				/* local version of n_lines */
Xint i ;
X
Xloc[n++] = 0 ;				/* first line */
X
X/*
X * check each character for a newline ('\n')
X */
X
Xstring_length = strlen(text) ;
Xfor (i=0;  i < string_length; i++)
X    {
X    if (text[i] == '\n')
X	{
X	if (n == FIND_NEWLINES_MAX_LINES)
X	    {
X	    XtWarning ("CuLabel: Too many newlines!") ;
X	    }
X	else
X	    {
X	    loc[n++] = i+1 ;		/* subsequent lines */
X	    text[i] = '\0' ;
X	    }
X	}
X    }
X
X/* allocate space for the calling array */
X*line_locations = (unsigned int *) XtMalloc (n * sizeof (unsigned int)) ;
X
X/* Now copy the line locations to the calling array */
Xfor (i=0;  i < n;  i++)
X    {
X    (*line_locations)[i] = loc[i] ;
X    }
X
X*n_lines = n ;
Xreturn ;
X}
X
Xstatic Dimension
XPreferredWidth (lw)
X    CuLabelWidget lw ;
X{
XDimension facet_add = (lw->simple.shadow ? 1 : 2) * lw->simple.facet_width ;
XDimension smallest_width = lw->label.total_width +
X		     2*lw->label.internal_width +
X		     facet_add ;
Xif (lw->label.big_label && lw->label.big_width > smallest_width)
X	return lw->label.big_width ;
Xelse
X    {
X    return smallest_width ;
X   }
X}
X
Xstatic Dimension
XPreferredHeight (lw)
X    CuLabelWidget lw ;
X{
XDimension facet_add = (lw->simple.shadow ? 1 : 2) * lw->simple.facet_width ;
XDimension smallest_height = lw->label.total_height +
X		     2*lw->label.internal_height +
X		     facet_add ;
Xif (lw->label.big_label && lw->label.big_height > smallest_height)
X	return lw->label.big_height ;
Xelse
X    {
X    return smallest_height ;
X   }
X}
X
X

END_OF_FILE
echo shar: NEWLINE appended to \"'src/CuLabel.c'\"
if test 26543 -ne `wc -c <'src/CuLabel.c'`; then
    echo shar: \"'src/CuLabel.c'\" unpacked with wrong size!
fi
# end of 'src/CuLabel.c'
fi
echo shar: End of archive 3 \(of 12\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 12 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0