CDSatellitesImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Louis Monier November 19, 1985 11:45:07 am PST
Pradeep Sindhu December 19, 1985 5:41:10 pm PST
Bertrand Serlet December 1, 1985 4:33:09 pm PST
DIRECTORY
CD, CDCells, CDDirectory, CDEvents, CDCommandOps, CDMenus, CDOps, CDPanelFonts, CDProperties, CDSatellites, CDSequencer, CDTexts,
IO,
PW,
TerminalIO;
CDSatellitesImpl: CEDAR PROGRAM
IMPORTS CDCells, CDDirectory, CDEvents, CDCommandOps, CDMenus, CDOps, CDPanelFonts, CDProperties, CDTexts, IO, PW, TerminalIO
EXPORTS CDSatellites =
BEGIN OPEN CDSatellites;
satellitesProp: ATOMPW.RegisterProp[$CDSatellites, TRUE];
This property hangs on a master. Its value is a list of CD.Objects that are the master's satellites.
Public functions
SetSatellites: PUBLIC PROC [master: CD.Instance, satellites: ObList ← NIL] = {
CDProperties.PutPropOnInstance[master, satellitesProp, satellites];
};
AddSatellites: PUBLIC PROC [master: CD.Instance, satellites: ObList ← NIL] = {
s: ObList ← NARROW[CDProperties.GetPropFromInstance[master, satellitesProp]];
FOR l: ObList ← satellites, l.rest WHILE l#NIL DO
s ← CONS[l.first, s]
ENDLOOP;
CDProperties.PutPropOnInstance[master, satellitesProp, s];
};
GetSatellites: PUBLIC PROC [master: CD.Instance] RETURNS [satellites: ObList ← NIL] = {
satellites ← NARROW [CDProperties.GetPropFromInstance[master, satellitesProp]];
};
GetSatelliteRopes: PUBLIC PROC [masterProps: CD.PropList] RETURNS [ropes: LIST OF ROPENIL] = {
FOR list: ObList ← NARROW [CDProperties.GetPropFromList[masterProps, satellitesProp]], list.rest WHILE list#NIL DO
rope: ROPENARROW [list.first.specificRef, CDTexts.TextPtr].text;
ropes ← CONS [rope, ropes];
ENDLOOP;
};
EnforceConstraint: PUBLIC PROC [world: LIST OF CD.Instance] RETURNS [allOk: BOOL] = {
allOk ← TRUE;
FOR iList: LIST OF CD.Instance ← world, iList.rest WHILE iList#NIL DO
oldObList: ObList ← NARROW [CDProperties.GetProp[iList.first, satellitesProp]];
newObList: ObList ← NIL;
thisOk: BOOLTRUE;
FOR oList: ObList ← oldObList, oList.rest WHILE oList#NIL DO
IF ExistsInstance[oList.first, world]
THEN newObList ← CONS[oList.first, newObList]
ELSE thisOk ← FALSE
ENDLOOP;
IF ~thisOk THEN {
CDProperties.PutProp[iList.first, satellitesProp, newObList]; allOk ← FALSE};
ENDLOOP;
};
Event Procs for reading and writing satellites from files
satelliteUniqueIDProp: ATOMPW.RegisterProp[$CDSatelliteUniqueID, TRUE];
Group number (saved on file)
BeforeOutput: CDEvents.EventProc = {
id: INT ← 0;
AddIDOnWorld: PROC [world: CD.InstanceList] = {
FOR list: CD.InstanceList ← world, list.rest WHILE list#NIL DO
satellites: ObList ← GetSatellites[list.first];
ref: REF INT;
IF satellites=NIL THEN LOOP;
ref ← NEW [INT ← id]; id ← id + 1;
CDProperties.PutPropOnInstance[list.first, satelliteUniqueIDProp, ref];
FOR sats: ObList ← satellites, sats.rest WHILE sats#NIL DO
CDProperties.PutPropOnObject[sats.first, satelliteUniqueIDProp, ref];
ENDLOOP;
ENDLOOP;
};
AddID: CDDirectory.EachEntryAction = {
IF ~CDCells.IsCell[ob] THEN RETURN;
AddIDOnWorld[NARROW [ob.specificRef, CD.CellPtr].contents];
};
[] ← CDDirectory.Enumerate[design, AddID];
AddIDOnWorld[CDOps.InstList[design]];
};
AfterInput: CDEvents.EventProc = {
UseIDOnWorld: PROC [world: CD.InstanceList] = {
FOR list: CD.InstanceList ← world, list.rest WHILE list#NIL DO
master: CD.Instance ← list.first;
satellites: ObList ← NIL;
refInt: REF INTNARROW [CDProperties.GetPropFromInstance[master, satelliteUniqueIDProp]];
IF refInt=NIL THEN LOOP;
FOR sats: CD.InstanceList ← world, sats.rest WHILE sats#NIL DO
sat: CD.Object ← sats.first.ob;
satRefInt: REF INTNARROW [CDProperties.GetPropFromObject[sat, satelliteUniqueIDProp]];
IF satRefInt=NIL OR satRefInt^#refInt^ THEN LOOP;
IF ~Member[satellites, sat] THEN satellites ← CONS [sat, satellites];
ENDLOOP;
SetSatellites[master, satellites];
ENDLOOP;
};
UseID: CDDirectory.EachEntryAction = {
IF ~CDCells.IsCell[ob] THEN RETURN;
UseIDOnWorld[NARROW [ob.specificRef, CD.CellPtr].contents];
};
[] ← CDDirectory.Enumerate[design, UseID];
UseIDOnWorld[CDOps.InstList[design]];
};
Event Proc for processing a cell change
AfterCellReplacement: CDEvents.EventProc = {
ob: CD.Object ← NARROW [x];
[] ← EnforceConstraint[NARROW[ob.specificRef, CD.CellPtr].contents];
};
Command Procs
Given a satellite or a master select the whole group.
SelectGroupCommand: PROC [comm: CDSequencer.Command] = {
world: CD.InstanceList ← CDOps.InstList[comm.design];
multiple: BOOL;
selected: CD.Instance;
numSats: INT;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~SingleSelected[selected, multiple] THEN RETURN;
IF CDTexts.IsText[selected.ob]
THEN numSats ← SelectGroup[comm.design, world, FindMaster[world, selected.ob]]
ELSE numSats ← SelectGroup[comm.design, world, selected];
TerminalIO.WriteF["Group selected: %g satellites(s) in group\n", IO.int[numSats]];
};
Adds a single satellite to those already existing for a master.
AddSatelliteCommand: PROC [comm: CDSequencer.Command] = {
selected: CD.Instance;
multiple: BOOL;
name: ROPE;
font: CDTexts.CDFont ← CDPanelFonts.CurrentFont[comm.design];
text: CD.Object;
[selected, multiple] ← CDOps.SelectedInstance[comm.design];
IF ~SingleSelected[selected, multiple] THEN RETURN;
IF CDTexts.IsText[selected.ob] THEN {
TerminalIO.WriteRope["\n** Selected instance is text--can't put a satellite on it.\n"];
RETURN;
};
name ← TerminalIO.RequestRope["Type Satellite: "];
IF name=NIL THEN {TerminalIO.WriteRope["\n** Empty name--can't do it.\n"]; RETURN};
IF font=NIL THEN {TerminalIO.WriteRope["\n** No current font--can't do it.\n"]; RETURN};
text ← CDTexts.CreateText[name, font];
CDOps.AddAnObject[design: comm.design, ob: text, location: comm.pos, orientation: 0];
AddSatellites[selected, LIST[text]];
TerminalIO.WriteRope["Satellite added\n"];
};
Given zero or more text instances and exactly one non-text instance (the master) remove any previous satellites and add the ones currently selected.
SetSatellitesCommand: PROC [comm: CDSequencer.Command] = {
world: CD.InstanceList ← CDOps.InstList[comm.design];
satellites: ObList ← NIL;
master: CD.Instance ← NIL;
FOR list: CD.InstanceList ← world, list.rest WHILE list#NIL DO
instance: CD.Instance ← list.first;
IF ~instance.selected THEN LOOP;
IF CDTexts.IsText[instance.ob]
THEN {
IF Member[satellites, instance.ob] THEN LOOP;
Look if some master in the world already has this satellite
IF FindMaster[world, instance.ob]#NIL THEN {
[] ← SelectGroup[comm.design, world, FindMaster[world, instance.ob]];
TerminalIO.WriteRope["\n** Some satellite is already in another group, which is now shown selected--not done.\n"];
RETURN;
};
satellites ← CONS [instance.ob, satellites];
}
ELSE {
IF master#NIL THEN {
TerminalIO.WriteRope["\n** More than one master selected--can't do it.\n"];
RETURN;
};
master ← instance;
};
ENDLOOP;
IF master=NIL THEN {
TerminalIO.WriteRope["\n** No master selected--can't do it.\n"];
RETURN;
};
SetSatellites[master, satellites];
TerminalIO.WriteRope["Satellites set\n"];
};
Check the satellite constraint and enforce it if it isn't satisfied
EnforceSatelliteConstraintCommand: PROC [comm: CDSequencer.Command] = {
ok: BOOL ← EnforceConstraint[CDOps.InstList[comm.design]];
IF ok
THEN TerminalIO.WriteRope["Satellite constraint ok.\n"]
ELSE TerminalIO.WriteRope["Satellite constraint NOT ok--enforcing it.\n"];
};
Internal Utilities
ExistsInstance: PROC [ob: CD.Object, world: LIST OF CD.Instance] RETURNS [BOOL] = {
FOR iList: LIST OF CD.Instance ← world, iList.rest WHILE iList#NIL DO
IF iList.first.ob=ob THEN RETURN [TRUE]
ENDLOOP;
RETURN [FALSE]
};
Member: PROC [objects: ObList, object: CD.Object] RETURNS [BOOLFALSE] = {
WHILE objects#NIL DO
IF objects.first=object THEN RETURN [TRUE]; objects ← objects.rest;
ENDLOOP;
};
FindMaster: PROC [world: LIST OF CD.Instance, satellite: CD.Object] RETURNS [master: CD.Instance ← NIL] = {
FOR list: CD.InstanceList ← world, list.rest WHILE list#NIL DO
IF Member[GetSatellites[list.first], satellite] THEN RETURN [list.first];
ENDLOOP;
};
SingleSelected: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL] = {
IF selected=NIL THEN {
TerminalIO.WriteRope["\n** No current selection--can't do it.\n"];
RETURN[FALSE];
};
IF multiple THEN {
TerminalIO.WriteRope["\n** Multiple instances selected--can't do it.\n"];
RETURN[FALSE];
};
RETURN[TRUE];
};
Select the satellite group for master
SelectGroup: PROC [design: CD.Design, world: LIST OF CD.Instance, master: CD.Instance] RETURNS [numSats: INT] = {
satellites: ObList;
numSats ← 0;
IF master=NIL THEN RETURN ELSE satellites ← GetSatellites[master];
FOR list: CD.InstanceList ← world, list.rest WHILE list#NIL DO
list.first.selected ← FALSE;
CDCommandOps.RedrawInstance[design, list.first];
ENDLOOP;
master.selected ← TRUE;
CDCommandOps.RedrawInstance[design, master];
FOR list: CD.InstanceList ← world, list.rest WHILE list#NIL DO
IF ~Member[satellites, list.first.ob] THEN LOOP;
list.first.selected ← TRUE; numSats ← numSats + 1;
CDCommandOps.RedrawInstance[design, list.first];
ENDLOOP;
};
Initialization
CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Select Group (O-Left)", p: SelectGroupCommand, key: $SelectGroup];
CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Add Satellite (O-Middle)", p: AddSatelliteCommand, key: $AddSatellite, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Set Satellites (O-Right)", p: SetSatellitesCommand, key: $SetSatellites, queue: doQueueAndMark];
CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Enforce Satellite Constraint", p: EnforceSatelliteConstraintCommand, key: $EnforceSatelliteConstraint, queue: doQueueAndMark];
CDEvents.RegisterEventProc[$BeforeOutput, BeforeOutput];
CDEvents.RegisterEventProc[$AfterInput, AfterInput];
CDEvents.RegisterEventProc[$AfterCellReplacement, AfterCellReplacement];
END.