DIRECTORY
AMTypes, AMBridge, Atom, Buttons, CD, CDCallSpecific, CDMenus, CDProperties, CDSequencer, CDViewer, Commander, Convert, IO, Menus, Process, Rope, TerminalIO, ViewRec, VFonts, ViewerClasses, ViewerOps;
CDEMMPropertiesTool:
CEDAR
MONITOR
IMPORTS AMTypes, AMBridge, Atom, Buttons, CDCallSpecific, CDMenus, CDProperties, CDSequencer, CDViewer, Commander, Convert,
IO, Process, Rope, TerminalIO, ViewRec, VFonts, ViewerOps =
BEGIN
CDPropValue: TYPE = REF ANY;
valueHandler: ViewRec.SimpleHandler =
NEW [ViewRec.SimpleHandlerRep ← [
Parse: ParseValue,
UnParse: UnParseValue,
Max: MaxValue,
Butt: NIL]];
valueInstance: REF CDPropValue = NEW[CDPropValue];
tvValueInstance: AMTypes.TypedVariable;
lastRope: Rope.ROPE ← NIL;
lastValueInstance: REF ANY ← NIL;
ParseValue:
PROC [asRope: Rope.
ROPE, tv: AMTypes.TypedVariable, targType: AMTypes.Type, handlerData:
REF
ANY]
RETURNS [ok:
BOOLEAN]
-- ViewRec.ParseProc -- =
BEGIN
i: INT;
isInt: BOOL ← TRUE;
ok ← TRUE;
lastRope ← asRope;
i ← Convert.IntFromRope[asRope ! Convert.Error => {isInt ← FALSE; CONTINUE}];
valueInstance^ ← lastValueInstance ← (
SELECT
TRUE
FROM
isInt => NEW[INT ← i],
asRope.Equal["NIL"] => NIL,
asRope.Length>0 AND asRope.Fetch[0] = '" => Convert.RopeFromLiteral[asRope],
asRope.Length>0 AND asRope.Fetch[0] = '$ => Convert.AtomFromRope[asRope],
ENDCASE => asRope);
AMTypes.Assign[tv, tvValueInstance ! AMTypes.Error =>
{ok ← FALSE; CONTINUE}];
END;
UnParseValue:
PROC [tv: AMTypes.TypedVariable, targType: AMTypes.Type, handlerData:
REF
ANY]
RETURNS [asRope: Rope.
ROPE]
-- ViewRec.UnParseProc -- =
BEGIN
AMTypes.Assign[tvValueInstance, tv];
asRope ← IO.PutR[IO.refAny[valueInstance^]];
END;
MaxValue:
PROC [tv: AMTypes.TypedVariable, targType: AMTypes.Type, handlerData:
REF
ANY]
RETURNS [maxWidthNeeded:
INTEGER, lines:
REAL ← 1]
-- ViewRec.MaxProc -- =
BEGIN
maxWidthNeeded ← 32*VFonts.StringWidth["X"];
END;
ValueRecognizer:
PROC [
t: AMTypes.Type, --unreduced
onlyRecognize: BOOLEAN,--don't bother to produce the handler and handlerData
specs: ViewRec.BindingList, --what will apply to this element
createOptions: ViewRec.CreateOptions--for aggregate containing this elt
]
RETURNS [
IKnowYou: BOOLEAN,
handler: ViewRec.Handler,
handlerData: REF ANY ← NIL] -- ViewRec.Recognizer -- =
BEGIN
handler ← valueHandler;
IKnowYou ← FALSE;
WHILE
NOT IKnowYou
DO
name: Rope.ROPE = AMTypes.TypeToName[t];
SELECT
TRUE
FROM
Rope.Equal[name, "CDPropValue"] => {IKnowYou ← TRUE};
AMTypes.TypeClass[t] = definition => t ← AMTypes.Ground[t];
ENDCASE => EXIT;
ENDLOOP;
END;
A p p l i c a t i o n s
PropertyToolState:
TYPE =
RECORD [
prop: ATOM ← $SignalName,
value: CDPropValue ← NIL
];
ButtonTable:
TYPE =
RECORD [
pts: REF PropertyToolState,
buttons:
SEQUENCE size:
NAT
OF
RECORD [
b: Buttons.Button,
p: PropertyToolState,
age: INT ← 0]];
ButtonInfo:
TYPE =
RECORD [
b: REF ButtonTable,
i: INT
];
pts: REF PropertyToolState ← NIL;
oldPts: REF PropertyToolState = NEW[PropertyToolState ← []];
PropertyToolUpdater:
PROC =
BEGIN
ptViewer: ViewerClasses.Viewer;
buttons: REF ButtonTable = NEW[ButtonTable[9]];
first: BOOL ← TRUE;
oldEntryName: Rope.ROPE ← "CDPropTool";
buttons.pts ← pts ← NEW[PropertyToolState ← []];
ptViewer ← ViewerOps.CreateViewer[flavor: $Container, info: [name: "CDPropTool", openHeight: 6*VFonts.FontHeight[]+50]];
FOR i:
INT
IN [0..buttons.size)
DO
buttons[i] ← [
b: Buttons.Create[
info: [
name: "SetPropOnSelected ",
parent: ptViewer,
wx: (
IF i
MOD 3 = 0
THEN 0
ELSE
buttons[i-1].b.wx+buttons[i-1].b.ww+2),
wy: (
IF i/3 = 0
THEN 0
ELSE
buttons[i-3].b.wy+buttons[i-3].b.wh+2)
],
proc: ButtonSetPropOnSelected, clientData: NEW[ButtonInfo ← [b: buttons, i: i]]],
p: [prop: NIL, value: NIL]];
ENDLOOP;
[] ← ViewRec.ViewRef[agg: pts, viewerInit: [parent: ptViewer, wy: buttons[buttons.size-1].b.wy+buttons[buttons.size-1].b.wh+2]];
DO
IF first
OR ResolveState[].changed
THEN
BEGIN
newEntryName: Rope.ROPE = Label[pts^];
ReplaceEntry:
PROC [menu:
ATOM] =
BEGIN
CDMenus.CreateEntry[menu: menu, entry: oldEntryName, key: NIL];
CDMenus.CreateEntry[menu: menu, entry: newEntryName, key: $CDPropToolSet];
END;
ReplaceEntry[menu: $NameMenuOnlyApp];
ReplaceEntry[menu: $NameMenuFull];
ReplaceEntry[menu: $NameMenuOnlyDesign];
oldEntryName ← newEntryName;
first ← FALSE;
END;
Process.Pause[Process.MsecToTicks[500]];
ENDLOOP;
END;
ResolveState:
ENTRY
PROC
RETURNS [ changed:
BOOL ] =
BEGIN
ENABLE UNWIND => pts ← NIL;
cpts: PropertyToolState ← GetValidPTS[];
SELECT
TRUE
FROM
cpts.prop = NIL => NULL;
cpts.prop # oldPts.prop =>
pts.value ← Atom.GetProp[$CDPropTool, cpts.prop];
cpts.value # oldPts.value => Atom.PutProp[$CDPropTool, cpts.prop, cpts.value];
cpts.value # Atom.GetProp[$CDPropTool, cpts.prop] =>
pts.value ← Atom.GetProp[$CDPropTool, cpts.prop];
ENDCASE => NULL;
changed ← cpts # oldPts^;
oldPts^ ← cpts;
END;
StartPropertyTool:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF ←
NIL, msg: Rope.
ROPE ←
NIL]
-- Commander.CommandProc -- =
BEGIN
CDSequencer.ImplementCommand[$CDPropToolSet, SetPropOnSelected];
IF pts = NIL THEN TRUSTED {Process.Detach[FORK PropertyToolUpdater[]]};
END;
Label:
PROC [ p: PropertyToolState ]
RETURNS [ r: Rope.
ROPE ] =
BEGIN
value: Rope.ROPE = IO.PutR[IO.refAny[pts.value]];
r ← IO.PutFR["%g←%g", IO.atom[pts.prop], IO.rope[(IF value.Length < 15 THEN value ELSE Rope.Cat[value.Substr[len: 15], "..."])]];
END;
GetValidPTS:
PROC
RETURNS [ p: PropertyToolState ] =
BEGIN
propProcs: CDProperties.PropertyProcs;
p ← pts^;
IF p.prop =
NIL
OR (propProcs ← CDProperties.FetchProcs[p.prop]) =
NIL
OR propProcs.exclusive
THEN {
IF p.prop # $IllegalProp
THEN
TerminalIO.WriteRope[
IO.PutFR["CDPropTool: Property %g is %g.\n",
IO.atom[p.prop],
IO.rope[(
SELECT
TRUE
FROM
propProcs = NIL => "not registered with ChipNDale",
propProcs.exclusive => "not allowed to be set by users",
ENDCASE => "not permitted")]]];
Atom.PutProp[$CDPropTool, $IllegalProp, NIL];
pts^ ← p ← [prop: $IllegalProp, value: NIL];
};
END;
age: INT ← 0;
ButtonSetPropOnSelected:
PROC [ parent:
REF
ANY, clientData:
REF
ANY ←
NIL,
mouseButton: Menus.MouseButton ← red, shift, control: BOOL ← FALSE ] -- Buttons.ButtonProc -- =
BEGIN
PutOnButton:
PROC [bt:
REF ButtonTable, p: PropertyToolState] =
BEGIN
oldest: INT ← 1;
FOR i:
INT
IN [1..bt.size)
DO
IF bt[i].p.prop = p.prop
THEN {
same: BOOL;
WITH p.value
SELECT
FROM
r: Rope.
ROPE =>
WITH bt[i].p.value
SELECT
FROM
r2: Rope.ROPE => same ← r.Equal[r2];
ENDCASE => same ← FALSE;
k:
REF
INT =>
WITH bt[i].p.value
SELECT
FROM
k2: REF INT => same ← k^ = k2^;
ENDCASE => same ← FALSE;
ENDCASE => same ← p.value = bt[i].p.value;
IF same THEN {bt[i].age ← age; RETURN};
};
IF bt[i].age < bt[oldest].age THEN oldest ← i;
ENDLOOP;
bt[oldest].p ← p;
bt[oldest].age ← age;
Buttons.ReLabel[button: bt[oldest].b, newName: Label[p]];
END;
bi: REF ButtonInfo = NARROW[clientData];
cpts: PropertyToolState ← bi.b[bi.i].p;
cdViewer: ViewerClasses.Viewer;
design: CD.Design;
age ← age+1;
IF cpts.prop #
NIL
THEN {
bi.b[bi.i].age ← age;
Atom.PutProp[$CDPropTool, bi.b[bi.i].p.prop, bi.b[bi.i].p.value];
bi.b.pts^ ← cpts;
}
ELSE {
cpts ← GetValidPTS[];
IF cpts.prop = $IllegalProp THEN RETURN;
PutOnButton[bi.b, cpts];
};
IF mouseButton = red
THEN {
IF (cdViewer ← CDViewer.LastViewer[]) #
NIL
AND
(design ← CDViewer.DesignOf[cdViewer].design) #
NIL
THEN
CDSequencer.ExecuteCommand[comm: NEW[CDSequencer.CommandRec ← [ref: NEW[PropertyToolState ← cpts]]], design: design, command: $CDPropToolSet]
ELSE TerminalIO.WriteRope["CDPropTool: Couldn't find design in which to set properties\n"]
};
END;
SetPropOnSelected:
ENTRY
PROC [ c: CDSequencer.Command ]
-- CDSequencer.CommandProc -- =
BEGIN
ENABLE UNWIND => NULL;
onOb: BOOL;
count: INT ← 0;
cpts: PropertyToolState;
DoSetProp:
PROC [design:
CD.Design, aptr:
CD.ApplicationPtr, x:
REF]
RETURNS [done: BOOL←TRUE, removeMe: BOOL←FALSE, include: CD.ApplicationList←NIL,
repaintMe:
BOOL←
FALSE, repaintInclude:
BOOL←
FALSE]
-- CDCallSpecific.CallProc -- =
BEGIN
IF onOb THEN CDProperties.PutPropOnObject[aptr.ob, cpts.prop, cpts.value]
ELSE CDProperties.PutPropOnApplication[aptr, cpts.prop, cpts.value];
count ← count+1;
END;
cpts ← (IF ISTYPE[c.ref, REF PropertyToolState] THEN NARROW[c.ref, REF PropertyToolState]^ ELSE GetValidPTS[]);
IF cpts.prop # $IllegalProp
THEN {
onOb ← (CDProperties.GetPropFromList[CDProperties.FetchProcs[cpts.prop].properties, $ObjectsOnly] # NIL);
[] ← CDCallSpecific.CallForSelected[design: c.design, whatElse: DoSetProp];
TerminalIO.WriteRope[
IO.PutFR["CDPropTool: %g set to %g in %g%d applications.\n",
IO.atom[cpts.prop], IO.refAny[cpts.value], IO.rope[(IF onOb THEN "objects underlying " ELSE "")], IO.int[count]]];
};
END;
TRUSTED {tvValueInstance ← AMBridge.TVForReferent[valueInstance]};
ViewRec.RegisterRecognizerBeforeReductions[r: ValueRecognizer, end: Front, applyBefore: EquivalenceClass];
[] ← CDProperties.RegisterProperty[$ObjectsOnly, $CDProperties];
CDProperties.InstallProcs[$ObjectsOnly, [
makeCopy: CDProperties.CopyVal,
internalWrite: CDProperties.RopePWrite,
internalRead: CDProperties.RopePRead]];
Commander.Register["CDPropTool", StartPropertyTool, "Tool for adding/changing ChipNDale properties"];
END.