FILE: [Ivy]<Spreitzer>Top>ViewRec.DF=>ViewRec.Mesa
last edited by Spreitzer October 30, 1983 6:22 pm
Last Edited by: Maxwell, November 16, 1982 3:28 pm
DIRECTORY
AMTypes, Buttons, List, Menus, Rope, ViewerClasses, VFonts;
ViewRec: CEDAR DEFINITIONS
IMPORTS VFonts =
BEGIN
Errors:
NotAnAggregate: ERROR;
raised by the create procs if not handed a record, structure (unpainted record), sequence, or array.
NoSelectedProc: ERROR;
raised by CallSelectedProc
AlreadyHandled: ERROR;
raised by registration procs
BadID: ERROR [id: Id];
raised by create procs and GetEltHandle.
NotFound: ERROR [name: Path];
raised by GetEltHandle.
Familiar Types:
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
TypedVariable: TYPE = AMTypes.TypedVariable;
Type: TYPE = AMTypes.Type;
New Types:
RecordViewer: TYPE = REF RecordViewerRep;
RecordViewerRep: TYPE;
BindingList: TYPE = LIST OF Binding;
Binding: TYPE = RECORD [
name: Id,
it: SELECT type: BindingType FROM
Value => [val: TypedVariable, visible, editable, dontAssign: BOOLEANFALSE],
Notify => [notify: NotifyClientProc, clientData: REF ANYNIL],
TryRecognizer => [recognizer: Recognizer],
Group => [sublist, altSublist: BindingList ← NIL],
ENDCASE];
Id: TYPE = REF ANY; --actually UNION [ROPE, REF TEXT, REF INT (origin 1) (negatives mean count from end), all];
all: REF ANY;
Path: TYPE = LIST OF Id; --outermost first
BindingType: TYPE = {Value, Notify, TryRecognizer, Group};
NotifyClientProc: TYPE = PROC [clientData: REF ANY];
NotifyList: TYPE = LIST OF NotifyRequest;
NotifyRequest: TYPE = RECORD [proc: NotifyClientProc, clientData: REF ANY];
Int: TYPE = REF INT;
--These control layout, and a few other things, which are done at create time.--
CreateOptions: TYPE = RECORD [
immProcFont: VFonts.Font ← NIL, --NIL means use Viewers default
preProcFont: VFonts.Font ← NIL, --font for prepared procedure names
doitFont: VFonts.Font ← NIL, --for the Doit button in Proc's args rec
stateFont: VFonts.Font ← NIL, --for the State label in Proc's args rec
nameFont: VFonts.Font ← NIL, --for first half of name:value pairs
labelFont: VFonts.Font ← NIL, --for the label of the RecordViewer
bordElts: BOOLEANFALSE, --draw border around every Name-Value pair
bordRecs: BOOLEANTRUE, --border a Value if it is a RECORD
bordImmProcs: BOOLEANTRUE, --border immediate PROCEDUREs
bordPreProcs: BOOLEANTRUE, --border prepared PROCEDUREs
bordDoit: BOOLEANTRUE, --border the Doit button in a Proc's args rec
bordState: BOOLEANFALSE, --border the State label in a Proc's args
vSep: CARDINAL ← 2,  --spacing between lines of stuff
hSep: CARDINAL ← 5,  --spacing between things on a line
vPad: CARDINAL ← 3,  --height of Value boxes, beyond font height
hPad: CARDINAL ← 13,  --width of Value boxes, beyond string width
nvSep: CARDINAL ← 3,  --seperation between Name and Value
vStilts: INTEGER ← -1,  --artificially lower the Name Label this much
feedBackHeight: CARDINAL ← 40, --how high the FeedBack Window is
minFeedBackWidth: CARDINAL ← 100, --unless height is 0, of course
minRecordWidth: CARDINAL ← 100, --lower bound for RECORDs
defaultTargetWidth: CARDINAL ← 400,
relayoutable: BOOLEANTRUE,
mayInitiateRelayout: BOOLEANTRUE,
maxEltsHeight: CARDINAL ← 290, --limits display for elements
maxArgsHeight: CARDINAL ← 310, --limits PROC arg display height
doAllRecords: BOOLEANFALSE,--if TRUE, every record is judged simple enough to attempt to display; components will still be judged individually
exclusiveProcs: BOOLEANTRUE, --makes procs mutually exclusive
holdOff: BOOLEANFALSE, --prevents actually calling PROCs
highlightSelectedProc: BOOLEANTRUE, --causes current Proc Button to display Black on Grey
other: List.AList ← NIL  --for expansion
];
OtherStuffProc: TYPE = PROC [in: Viewer] RETURNS [stuff: LIST OF Viewer];
ButtonClick: TYPE = RECORD [
button: Buttons.Button ← NIL,
mouseButton: Menus.MouseButton ← red,
shift, control: BOOLEANFALSE];
EltHandle: TYPE = REF ANY; --type system lets us down
A handle on the display of an element of an aggregate.
Creating RecordViewers:
ViewTV: PROC [agg: TypedVariable,
specs: BindingList ← NIL,
label: ROPENIL,
otherStuff: OtherStuffProc ← NIL,
toButt: ButtonClick ← [],
parent: RecordViewer ← NIL,
asElement: EltHandle ← NIL,
sample: BOOLEANTRUE,
createOptions: CreateOptions ← [],
viewerInit: ViewerClasses.ViewerRec ← [],
paint: BOOLEANTRUE]
RETURNS [rv: RecordViewer];
This is it: Create a RecordViewer on "agg".
"specs" says some random things about components:
A Value binding will cause that component to be initialized to the given value; furthermore, this prevents that component from making the aggregate it is part of too complicated to handle.
Setting "dontAssign" prevents this intialization.
Setting "visible" FALSE will prevent the bound component from appearing on the screen.
Setting "editable" FALSE will ensure that it will not be editable.
A Notify binding causes ViewRec to call the given NotifyClientProc whenever ViewRec changes the value of that component (and maybe some other times as well).
Group bindings are the method by which components of nested records are addressed.
the "altSublist" applies to the return record of procedures; the "sublist" applies to embedded aggregates and the argument record of procedures.
A TryRecognizer binding is how Clients may specify their own ways of handling components (see the section on "Introducing new ways of displaying things").
If the last char of "label" is CR, it will be the sole occupant of the first line.
The OtherStuffProc produces a set of viewers to put at the beginning of the RecordViewer.
The ButtonClick is invoked when CONTROL-RETURN is typed in a Value Viewer by the User.
The "parent" is independant of the Viewers ancestry; it is used for finding a FeedBack Window.
If this is being applied to an aggregate embedded in an aggregate viewed with ViewRec, pass the EltHandle for this in "asElement" (to make Next and Previous work correctly).
"sample" causes this RecordViewer to be put on a list of RV's to be sampled in the background to keep its display up to date.
"viewerInit" is for the usual Viewers initing stuff, except:
for ww:
the RecordViewer lays itself out to the inner width of the Viewer created,
unless ww#0 and viewerInit.parent=NIL, in which case ww is used,
or unless ww=0 and (viewerInit.parent#NIL OR iconic), in which case createOptions.minRecordViewerWidth is used.
for name:
If name = NIL, then we try GetName[agg].
if "paint", then painted when done.
ViewRef: PROC [agg: REF ANY,
specs: BindingList ← NIL,
label: ROPENIL,
otherStuff: OtherStuffProc ← NIL,
toButt: ButtonClick ← [],
parent: RecordViewer ← NIL,
asElement: EltHandle ← NIL,
sample: BOOLEANTRUE,
createOptions: CreateOptions ← [],
viewerInit: ViewerClasses.ViewerRec ← [],
paint: BOOLEANTRUE]
RETURNS [rv: RecordViewer];
ViewRef is just like ViewTV, except it takes a REF to a record.
ViewInterface: PROC [name: ROPE,
specs: BindingList ← NIL,
label: ROPE ← NIL,
otherStuff: OtherStuffProc ← NIL,
toButt: ButtonClick ← [],
parent: RecordViewer ← NIL,
asElement: EltHandle ← NIL,
sample: BOOLEANTRUE,
createOptions: CreateOptions ← [],
viewerInit: ViewerClasses.ViewerRec ← [],
paint: BOOLEANTRUE]
RETURNS [RecordViewer];
makes a top-level RecordViewer on an Interface Record from a DEFINITIONs module
ViewSelf: PROC;
invokes ViewInterface on ViewRec
BindingList manipulations:
BindAllOfATypeFromTVs: PROC [
aggType, eltType: Type,
name: ROPENIL,
b: Binding --fill the "it" field with what you want
] RETURNS [BindingList];
returns a binding list where everything in "aggType" whose type = "eltType", and whose name = "name", gets bound according to the b.it;
IF name = NIL, THEN the name test is ignored.
BindAllOfATypeFromRefs: PROC [rec, handle: REF ANY, name: ROPENIL, visible, editable, dontAssign: BOOLEANFALSE]
RETURNS [BindingList];
Uses BindAllOfATypeFromTVs to make Value Bindings. The value used is the REFERENT of handle (NOT handle itself). For instance, to bind all Viewer variables to the value in v1, say "handle: NEW [Viewer ← v1]", not "handle: v1".
BindAllOfANameInType: PROC [agType: Type, name: ROPE, b: Binding] RETURNS [bl: BindingList];
BindAllOfANameFromRef: PROC [agInst: REF ANY, name: ROPE, val: REF ANY, visible, editable, dontAssign: BOOLEANFALSE] RETURNS [bl: BindingList];
BindingListAppend: PROC [a, b: BindingList] RETURNS [c: BindingList];
This is destructive (i.e. non-functional: it may alter CDR of last CONS cell in "a").
Things to do with RecordViewers once they have been created:
ReLayout: PROC [rv: RecordViewer, targetWidth: INTEGER ← 0, paint: BOOLEAN];
SampleRV: PROC [rv: RecordViewer];
Ensures that the current values are displayed
RedisplayElt: PROC [eh: REF ANY];
Ensures that the current value of this component is displayed.
CallSelectedProc: PROC [in: RecordViewer] RETURNS [refused: BOOLEAN];
DisplayMessage: PROC [rv: RecordViewer, msg: ROPE];
The msg is displayed wherever messages from this RecordViewer are displayed; the message is appended to the others already there, unless it is:
clearMessagePlace: READONLY ROPE;
this message will clear out wherever messages are going to.
SetUserAbort: PROC [who: REF ANY, newLevel: CARDINAL ← 100];
If who gets a RecordViewer, one of its procedure invocations (if any) is the subject;
If who gets an EltHandle, the running invocation of that procedure is the subject.
IncrementUserAbort: PROC [who: REF ANY, deltaLevel: INTEGER];
TestUserAbort: PROC [who: REF ANY] RETURNS [abort: CARDINAL];
TestAndMaybeResetUserAbort: PROC [who: REF ANY, threshold: CARDINAL ← 100] RETURNS [abort: CARDINAL --will be 0 or >= threshold--];
If it was >= threshold, it is reset to 0, and the old value returned; otherwise it is left as it was, and 0 is returned.
ProcessAbort: PROC [who: REF ANY] RETURNS [found: BOOLEAN];
Calls Process.Abort on the running proc, if any.
GetEltHandle: PROC [rv: RecordViewer, name: Path] RETURNS [eh: EltHandle];
RAISES NotFound[tail(i)[name]] when lost at i'th step.
SIMULA-style coersions between CLASSes:
RVQuaViewer: PROC [RecordViewer] RETURNS [Viewer];
ViewerIsRV: PROC [Viewer] RETURNS [BOOLEAN];
ViewerQuaRV: PROC [Viewer] RETURNS [RecordViewer];
NarrowToRV: PROC [REF ANY] RETURNS [RecordViewer];
For the fun of it:
Help: PROC;
opens a viewer on the document
GetName: PROC [tv: TypedVariable --record or structure--] RETURNS [name: ROPE];
Finds a field named "name", if any, and returns contents as rope, if possible.
Returns NIL if not possible.
Introducing new ways of displaying things:
RegisterRecognizerByType: PROC [r: Recognizer, end: AddPlace, type: Type--unreduced--, reductions: Reductions];
RegisterRecognizerBeforeReductions: PROC [r: Recognizer, end: AddPlace, applyBefore: Reductions];
RegisterRecognizerToApplyAfterAll: PROC [r: Recognizer, end: AddPlace];
Reductions: TYPE = {EquivalenceClass, StripSubranges, TypeClass};
AddPlace: TYPE = {Front, Back--of list of others already there--};
Recognizer: TYPE =
PROC [
t: Type,  --unreduced
onlyRecognize: BOOLEAN,--don't bother to produce the handler and handlerData
specs: BindingList, --what will apply to this element
createOptions: CreateOptions--for aggregate containing this elt
]
RETURNS [
IKnowYou: BOOLEAN,
handler: Handler,
handlerData: REF ANYNIL];
Handler: TYPE = REF ANY; --actually UNION {SimpleHandler, ComplexHandler}
SimpleHandler: TYPE = REF SimpleHandlerRep;
SimpleHandlerRep: TYPE = RECORD [
Parse: ParseProc, --NIL => read-only operation
UnParse: UnParseProc,
Max: MaxProc,
Butt: ButtProc ← NIL, --NIL => no meaning for Right (Blue) mouse button.
blueDoc: ROPENIL--tells what can be done with Right Button
];
ParseProc: TYPE = PROC [asRope: ROPE, tv: TypedVariable, targType: Type, handlerData: REF ANY] RETURNS [ok: BOOLEAN];
UnParseProc: TYPE = PROC [tv: TypedVariable, targType: Type, handlerData: REF ANY] RETURNS [asRope: ROPE];
MaxProc: TYPE = PROC [tv: TypedVariable, targType: Type, handlerData: REF ANY] RETURNS [maxWidthNeeded: INTEGER, lines: REAL ← 1];
ButtProc: TYPE = PROC [tv: TypedVariable, targType: Type, handler: SimpleHandler, handlerData: REF ANY, shift: BOOLEAN] RETURNS [new: TypedVariable, msg: ROPENIL];
ComplexHandler: TYPE = REF ComplexHandlerRep;
ComplexHandlerRep: TYPE = RECORD [
producer: ComplexProducer,
Responsible for putting up the viewer for the element.
relayouter: ReLayouter ← NIL,
updater: Updater,
Called when change of value detected.
elementGiver: ElementGiver ← NIL
If this element is an aggregate, this is for getting its elements.
];
ComplexProducer: TYPE = PROC [tv: TypedVariable, context: Context, handlerData: REF ANY] RETURNS [v: Viewer, clientData: REF ANY, sampleable: BOOLEANTRUE];
ReLayouter: TYPE = PROC [v: Viewer, maxWidth: INTEGER, handlerData, clientData: REF ANY];
Updater: TYPE = PROC [tv: TypedVariable, v: Viewer, handlerData, clientData: REF ANY];
ElementGiver: TYPE = PROC [agg: TypedVariable, which: Id, handlerData, clientData: REF ANY] RETURNS [eh: EltHandle];
Context: TYPE = RECORD [
main: Viewer,
for: RecordViewer,
maxWidth: INTEGER,
name: ROPE,
thisElement: EltHandle,
createOptions: CreateOptions,
notifies: NotifyList,
bindings: BindingList,
toButt: ButtonClick];
FinishPendingBusiness: PROC RETURNS [okToProceed: BOOLEAN];
Upon user action in a Complex Viewer, first call this proc to get permission to handle it.
SetPendingBusiness: PROC [proc: FinishProc ← NIL, data: REF ANYNIL];
FinishProc: TYPE = PROC [data: REF ANY] RETURNS [okToProceed: BOOLEAN];
RecognizeRope, RecognizeAtom, RecognizeNumber, RecognizeEnumeration, RecognizeRecord, RecognizeSequence--also works on ARRAYs--: Recognizer;
SimpleEnough: PROC [rt: --an aggregate--Type, specs: BindingList, createOptions: CreateOptions] RETURNS [ok: BOOLEAN, count--of visible elements--: CARDINAL];
RightFont: PROC [f: VFonts.Font] RETURNS [rf: VFonts.Font] = INLINE
{RETURN [IF f = NIL THEN VFonts.defaultFont ELSE f]};
For controling the sampling process:
BehaviorOptions: TYPE = RECORD [
delayParms: DelayParms ← [] --controls delay in sampling process
];
These parameters determine the number of milliseconds to pause:
DelayParms: TYPE = RECORD [
min: REAL ← 200,
max: REAL ← 3000,
offset: REAL ← 0,
dActive: REAL ← 0,
dExtant: REAL ← 0,
dElt: REAL ← 0,
dMicroseconds: REAL ← 4E-3, --wait 4 times as long as you work
priority: DelayPriority ← Normal];
DelayPriority: TYPE = {Normal, Background, Foreground};
delayed: READONLY REAL; --running average of sample time, weights are z**n
z: REAL;
behavior: BehaviorOptions;
these are the bits actually used
SetBehavior: PROC [newBehavior: BehaviorOptions ← []];
to set them all at once
END.