DIRECTORY CD, CDCells, CDDirectory, CDEvents, CDCommandOps, CDInstances, CDMenus, CDOps, CDPanelFonts, CDProperties, CDSatellites, CDSequencer, CDTexts, IO, TerminalIO; CDSatellitesImpl: CEDAR PROGRAM IMPORTS CDEvents, CDCommandOps, CDDirectory, CDInstances, CDMenus, CDOps, CDPanelFonts, CDProperties, CDTexts, IO, TerminalIO EXPORTS CDSatellites = BEGIN OPEN CDSatellites; satellitesProp: PUBLIC ATOM _ RegisterProp[$CDSatellitesSatList, TRUE]; maxGroupIdProp: PUBLIC ATOM _ RegisterProp[$CDSatellitesMaxGroupId, TRUE]; groupIdProp: PUBLIC ATOM _ RegisterProp[$CDSatellitesGroupId, TRUE]; prevNumMasters: NAT _ 0; AddSatellite: PUBLIC PROC [design: CD.Design, master: CD.Instance, satellite: CD.Instance] = { EnsureSatelliteOnList[master, satellite]; IF CDProperties.GetProp[master, groupIdProp]=NIL THEN { ref: REF INT _ NARROW[CDProperties.GetProp[design, maxGroupIdProp]]; ref^ _ ref^+1; CDProperties.PutProp[master, groupIdProp, NEW [INT _ ref^]]; }; CDProperties.PutProp[satellite, groupIdProp, NEW[INT _ GroupId[master]]]; }; RemoveSatellite: PUBLIC PROC [world: InstanceList, satellite: CD.Instance] = { sats: InstanceList; master: CD.Instance _ FindMaster[world, satellite]; CDProperties.PutProp[satellite, groupIdProp, NIL]; IF master=NIL OR CDProperties.GetProp[master, satellitesProp]=NIL THEN RETURN; sats _ NARROW[CDProperties.GetProp[master, satellitesProp]]; FOR sl: InstanceList _ NARROW[CDProperties.GetProp[master, satellitesProp]], sl.rest WHILE sl#NIL DO IF sl.first#satellite THEN sats _ CONS[sl.first, sats] ENDLOOP; CDProperties.PutProp[master, satellitesProp, sats] }; GetSatellites: PUBLIC PROC [master: CD.Instance] RETURNS [satellites: InstanceList _ NIL] = { satellites _ NARROW [CDProperties.GetPropFromInstance[master, satellitesProp]]; }; GetSatelliteRopes: PUBLIC PROC [masterProps: CD.PropList] RETURNS [ropes: LIST OF ROPE _ NIL] = { FOR list: InstanceList _ NARROW [CDProperties.GetPropFromList[masterProps, satellitesProp]], list.rest WHILE list#NIL DO rope: ROPE _ NARROW [list.first.ob.specificRef, CDTexts.TextPtr].text; ropes _ CONS [rope, ropes]; ENDLOOP; }; EnforceInvariants: PUBLIC PROC [design: CD.Design, world: InstanceList] = { Node: TYPE = REF NodeRec; NodeRec: TYPE = RECORD [ id: INT _ -1, list: InstanceList _ NIL]; Table: TYPE = REF TableRec; TableRec: TYPE = RECORD [ elements: SEQUENCE size: NAT OF LIST OF Node ]; masterTable: Table _ NEW[TableRec[TableSize[]]]; satelliteList: InstanceList; maxGroupId: INT; TableSize: PROC [] RETURNS [NAT] = INLINE { FOR sizes: LIST OF NAT _ LIST [7, 17, 31, 67, 253], sizes.rest WHILE sizes#NIL DO IF prevNumMasters <= sizes.first THEN RETURN [sizes.first] ENDLOOP; RETURN [253] }; Hash: PROC [i: INT] RETURNS [INT] = { RETURN[i MOD masterTable.size] }; Store: PROC [inst: CD.Instance] = { id: INT _ GroupIdFast[inst]; hash: INT _ Hash[id]; FOR nl: LIST OF Node _ masterTable[hash], nl.rest WHILE nl#NIL DO IF nl.first.id=id THEN {nl.first.list _ CONS[inst, nl.first.list]; RETURN}; ENDLOOP; masterTable[hash] _ CONS[NEW[NodeRec _ [id: id, list: LIST[inst]]], masterTable[hash]]; }; Fetch: PROC [id: INT] RETURNS [InstanceList] = { hash: INT _ Hash[id]; FOR nl: LIST OF Node _ masterTable[hash], nl.rest WHILE nl#NIL DO IF nl.first.id=id THEN RETURN [nl.first.list]; ENDLOOP; RETURN [NIL]; }; IF CDProperties.GetProp[design, maxGroupIdProp]=NIL THEN CDProperties.PutProp[design, maxGroupIdProp, NEW [INT _ 0]]; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO IF CDTexts.IsText[w.first.ob] THEN {IF CDProperties.GetProp[w.first, groupIdProp]#NIL THEN satelliteList _ CONS [w.first, satelliteList]} ELSE {IF CDProperties.GetProp[w.first, groupIdProp]#NIL THEN {Store[w.first]; CDProperties.PutProp[w.first, satellitesProp, NIL]}} ENDLOOP; FOR sl: InstanceList _ satelliteList, sl.rest WHILE sl#NIL DO Closer: PROC [newMaster: CD.Instance] RETURNS [BOOL] = INLINE { mRect, newMRect, sRect: CD.Rect; IF master=NIL THEN RETURN [TRUE]; mRect _ CDInstances.InstRectO[master]; newMRect _ CDInstances.InstRectO[newMaster]; sRect _ CDInstances.InstRectO[sl.first]; RETURN[RectMinDist[newMRect, sRect] < RectMinDist[mRect, sRect]]; }; master: CD.Instance _ NIL; satGId: INT _ GroupIdFast[sl.first]; FOR ml: InstanceList _ Fetch[satGId], ml.rest WHILE ml#NIL DO IF satGId#GroupIdFast[ml.first] THEN LOOP; IF Closer[ml.first] THEN master _ ml.first; ENDLOOP; IF master=NIL THEN CDProperties.PutProp[sl.first, groupIdProp, NIL] ELSE EnsureSatelliteOnList[master, sl.first]; ENDLOOP; maxGroupId _ NARROW [CDProperties.GetProp[design, maxGroupIdProp], REF INT]^; prevNumMasters _ 0; FOR i: INT IN [0..masterTable.size) DO FOR nl: LIST OF Node _ masterTable[i], nl.rest WHILE nl#NIL DO prevNumMasters _ prevNumMasters+1; FOR ml: InstanceList _ nl.first.list.rest, ml.rest WHILE ml#NIL DO maxGroupId _ maxGroupId+1; CDProperties.PutProp[ml.first, groupIdProp, NEW [INT _ maxGroupId]]; FOR sl: InstanceList _ NARROW[CDProperties.GetProp[ml.first, satellitesProp]], sl.rest WHILE sl#NIL DO CDProperties.PutProp[sl.first, groupIdProp, NEW [INT _ maxGroupId]]; ENDLOOP; ENDLOOP; ENDLOOP; ENDLOOP; CDProperties.PutProp[design, maxGroupIdProp, NEW [INT _ maxGroupId]] }; BeforeOutput: CDEvents.EventProc = { [] _ EnforceInvariants[design, CDOps.InstList[design]] }; AfterInput: CDEvents.EventProc = { EnforceForEachCell: CDDirectory.EachEntryAction = { [] _ EnforceInvariants[design, NARROW[ob.specificRef, CD.CellPtr].contents] }; [] _ CDDirectory.Enumerate[design, EnforceForEachCell]; [] _ EnforceInvariants[design, CDOps.InstList[design]] }; AfterCellReplacement: CDEvents.EventProc = { ob: CD.Object _ NARROW [x]; [] _ EnforceInvariants[design, NARROW[ob.specificRef, CD.CellPtr].contents]; }; SelectGroupCommand: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; multiple: BOOL; selected: CD.Instance; numSats: INT; [] _ EnforceInvariants[comm.design, world]; [selected, multiple] _ CDOps.SelectedInstance[comm.design]; IF ~SingleSelected[selected, multiple] THEN RETURN; IF CDProperties.GetProp[selected, groupIdProp]=NIL THEN { TerminalIO.WriteRope["Selected instance is not in any group.\n"]; RETURN }; IF CDTexts.IsText[selected.ob] THEN numSats _ SelectGroup[comm.design, world, FindMaster[world, selected]] ELSE numSats _ SelectGroup[comm.design, world, selected]; TerminalIO.WriteF["Group selected: %g satellites(s) in group.\n", IO.int[numSats]]; }; AddSatelliteCommand: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; multiple: BOOL; selected: CD.Instance; name: ROPE; font: CDTexts.CDFont _ CDPanelFonts.CurrentFont[comm.design]; text: CD.Instance; [] _ EnforceInvariants[comm.design, world]; [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 _ NEW [CD.InstanceRep _ [ob: CDTexts.CreateText[name, font], location: comm.pos]]; CDOps.IncludeInstance[comm.design, text]; AddSatellite[comm.design, selected, text]; TerminalIO.WriteRope["Satellite added\n"]; }; SetSatellitesCommand: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; satellites: InstanceList _ NIL; master: CD.Instance _ NIL; [] _ EnforceInvariants[comm.design, world]; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO inst: CD.Instance _ w.first; IF ~inst.selected THEN LOOP; IF CDTexts.IsText[inst.ob] THEN satellites _ CONS[inst, satellites] ELSE { IF master#NIL THEN {TerminalIO.WriteRope["\n** More than one master selected--can't do it.\n"]; RETURN}; master _ inst} ENDLOOP; IF master=NIL THEN {TerminalIO.WriteRope["\n** No master selected--can't do it.\n"]; RETURN}; IF CDProperties.GetProp[master, satellitesProp]#NIL THEN FOR sl: InstanceList _ NARROW [CDProperties.GetProp[master, satellitesProp]], sl.rest WHILE sl#NIL DO RemoveSatellite[world, sl.first]; ENDLOOP; FOR sl: InstanceList _ satellites, sl.rest WHILE sl#NIL DO RemoveSatellite[world, sl.first]; AddSatellite[comm.design, master, sl.first]; ENDLOOP; TerminalIO.WriteRope["Satellites set\n"]; }; GroupId: PROC [inst: CD.Instance] RETURNS [INT] = INLINE { IF CDProperties.GetProp[inst, groupIdProp]#NIL THEN RETURN[NARROW[CDProperties.GetProp[inst, groupIdProp], REF INT]^] ELSE RETURN[-1]; }; GroupIdFast: PROC [inst: CD.Instance] RETURNS [INT] = INLINE { RETURN[NARROW[CDProperties.GetProp[inst, groupIdProp], REF INT]^] }; EnsureSatelliteOnList: PROC [master: CD.Instance, satellite: CD.Instance] = { sats: InstanceList; IF CDProperties.GetPropFromInstance[master, satellitesProp]=NIL THEN sats _ LIST[satellite] ELSE { sats _ NARROW[CDProperties.GetPropFromInstance[master, satellitesProp], InstanceList]; IF ~Member[sats, satellite] THEN sats _ CONS[satellite, sats]; }; CDProperties.PutPropOnInstance[master, satellitesProp, sats]; }; Member: PROC [insances: InstanceList, inst: CD.Instance] RETURNS [BOOL _ FALSE] = { WHILE insances#NIL DO IF insances.first=inst THEN RETURN [TRUE]; insances _ insances.rest; ENDLOOP; }; GroupMember: PROC [instances: InstanceList, inst: CD.Instance] RETURNS [BOOL _ FALSE] = { instGId: INT _ GroupId[inst]; WHILE instances#NIL DO IF GroupId[instances.first]=instGId THEN RETURN [TRUE]; instances _ instances.rest; ENDLOOP; }; FindMaster: PROC [world: InstanceList, satellite: CD.Instance] RETURNS [master: CD.Instance _ NIL] = { satGId: INT _ GroupId[satellite]; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO IF satGId=GroupId[w.first] AND ~CDTexts.IsText[w.first.ob] THEN RETURN [w.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]; }; SelectGroup: PROC [design: CD.Design, world: LIST OF CD.Instance, master: CD.Instance] RETURNS [numSats: INT] = { satellites: InstanceList; numSats _ 0; IF master=NIL THEN RETURN ELSE satellites _ GetSatellites[master]; master.selected _ TRUE; CDCommandOps.RedrawInstance[design, master]; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO IF ~Member[satellites, w.first] THEN LOOP; w.first.selected _ TRUE; numSats _ numSats + 1; CDCommandOps.RedrawInstance[design, w.first]; ENDLOOP; }; IntervalMinDist: PROC [i1min, i1max, i2min, i2max: INT] RETURNS [INT] = INLINE { IF i1maxi2max THEN RETURN [i1min-i2max]; RETURN [0]; }; RectMinDist: PROC [rectA, rectB: CD.Rect] RETURNS [INT] = INLINE { xMinDist: INT _ IntervalMinDist[rectA.x1, rectA.x2, rectB.x1, rectB.x2]; yMinDist: INT _ IntervalMinDist[rectA.y1, rectA.y2, rectB.y1, rectB.y2]; IF xMinDist=0 THEN IF yMinDist=0 THEN RETURN [0] ELSE RETURN [yMinDist] ELSE IF yMinDist=0 THEN RETURN [xMinDist] ELSE RETURN [xMinDist+yMinDist] }; RegisterProp: PROC [prop: ATOM, copy: BOOL _ FALSE] RETURNS [sameAtom: ATOM] = { [] _ CDProperties.RegisterProperty[prop, $CDSatellites]; CDProperties.InstallProcs[prop, [makeCopy: IF copy THEN CDProperties.CopyVal ELSE CDProperties.DontCopy]]; sameAtom _ prop; }; [] _ CDMenus.CreateMenu["Satellite and Expressions", $SatellitesMenu]; CDMenus.ImplementMenuCommand[$SatellitesMenu, $SatellitesMenu]; CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Show Satellite Group (L-Left)", p: SelectGroupCommand, key: $SelectGroup]; CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Add Satellite (L-Middle)", p: AddSatelliteCommand, key: $AddSatellite, queue: doQueueAndMark]; CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Set Satellites (L-Right)", p: SetSatellitesCommand, key: $SetSatellites, queue: doQueueAndMark]; CDEvents.RegisterEventProc[$BeforeOutput, BeforeOutput]; CDEvents.RegisterEventProc[$AfterInput, AfterInput]; CDEvents.RegisterEventProc[$AfterCellReplacement, AfterCellReplacement]; END. ZCDSatellitesImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Written by Pradeep Sindhu December 20, 1985 1:25:44 pm PST This module is descended from the early implementation of satellites by Monier. It has been rewritten a number of times since then by Sindhu and Serlet to find an implementation that is comfortable to use both from programs and interactively. This last version is a complete rewrite, one hopes for the last time! Pradeep Sindhu January 31, 1986 3:55:28 pm PST This property hangs on a master. Its value is the list of the master's satellites. This property hangs on a design. Its value is the highest numbered satellite group in the design. This property hangs on each instance that is in a satellite group. Its value is the group's groupId. Public functions Check that maxGroupIdProp exists; if not, put it Make masterTable and satelliteList; at the same time strip masters of their satellite lists For each satellite find its closest master and put it on that master's satellite list Now go through the masterTable and renumber groups with identical group Id's Event Procs for reading and writing satellites from files Event Proc for processing a cell change Command Procs Given a satellite or a master select the whole group. Adds a single satellite to those already existing for a master. Given zero or more text instances and exactly one non-text instance (the master) remove any previous satellites and add the ones currently selected. Find the master and put selected text onto the list of satellites Remove master's old satellites, if any Remove each satellite from its previous master, if any, and put it on to the new one Internal Utilities Returns true if inst is in the list insances Returns true if some instance in intances has the same group Id as inst. Select the satellite group for master Initialization Κ– "cedar" style˜codešœ™Kšœ Οmœ1™<™:J™\J™ZJ™\J™%—K™.—K™šΟk œ˜ Kšžœžœ ˜ž—K˜•StartOfExpansion[]šΠblœžœž˜Kšžœhžœ ˜}Kšžœ˜Kšžœžœ˜K˜šœž œ&žœ˜GJšœR™R—šœž œ)žœ˜JJšœa™a—šœ ž œ&žœ˜DJšœd™d—K˜Kšœžœ˜Ihead™š Οn œžœžœ žœžœžœ˜^Kšœ)˜)šžœ+žœžœ˜7Kšœžœžœžœ/˜DK˜Kšœ*žœžœ ˜Kšœ"˜"šžœ0žœžœž˜BK˜Kšœ,žœžœ˜Dš žœžœ:žœžœž˜fKšœ,žœžœ˜DKšžœ˜—Kšžœ˜—Kšžœ˜—Kšžœ˜—Kšœ-žœžœ˜DKšœ˜—K˜L™9J˜šΟb œ˜$Jšœ6˜6Jšœ˜—J˜š‘ œ˜"š œ!˜3Jšœžœžœ˜KJ˜J˜—Jšœ7˜7Jšœ6˜6Jšœ˜—L™L™'š œ˜,Kšœžœ žœ˜Kšœžœžœ˜LK˜—L™ K™7š œžœ ˜8Kšœ2˜2Kšœ žœ˜Kšœ žœ ˜Kšœ žœ˜ K˜K˜+K˜Kšœ;˜;Kšžœ%žœžœ˜3šžœ-žœžœž˜9KšœA˜AKšž˜Kšœ˜—K˜šžœ˜KšžœG˜KKšžœ5˜9—KšœBžœ˜SKšœ˜—K˜K™?š œžœ ˜9Kšœ2˜2Kšœ žœ˜Kšœ žœ ˜Kšœžœ˜ Kšœ=˜=Kšœžœ ˜K˜K˜+K˜Kšœ;˜;Kšžœ%žœžœ˜3šžœžœ˜%K˜WKšžœ˜K˜—K˜Kšœ2˜2Kšžœžœžœ;žœ˜SKšžœžœžœ@žœ˜XKšœžœžœI˜WK˜)Kšœ*˜*K˜*Kšœ˜—K™K™”š œžœ ˜:Kšœ2˜2Kšœžœ˜Kšœžœ žœ˜K˜K˜+K™K™Ašžœ!žœžœž˜2Kšœžœ˜Kšžœžœžœ˜šžœ˜Kšžœžœ˜(šžœ˜KšžœžœžœNžœ˜hK˜——Kšžœ˜—KšžœžœžœCžœ˜]K™K™&šžœ.žœž˜8š žœžœ9žœžœž˜eK˜!Kšžœ˜——K™K™Tšžœ(žœžœž˜:K˜!K˜,Kšžœ˜—K˜)Kšœ˜—K˜L™š  œžœžœ žœžœžœ˜:šžœ)ž˜.Kš žœžœžœ*žœžœ˜FKšžœžœ˜—K˜—K˜š   œžœžœ žœžœžœ˜>Kšžœžœ*žœžœ˜AK˜—K˜š œžœ žœžœ˜MKšœ˜šžœ:ž˜?Kšžœžœ ˜šžœ˜KšœžœI˜VKšžœžœžœ˜>K˜——Kšœ=˜=K˜—K˜Kšœ,™,š  œžœ žœ žœžœžœ˜Sšžœ žœžœ˜Kšžœžœžœžœ˜DKšžœ˜—Kšœ˜K˜—K™Hš   œžœ!žœ žœžœžœ˜YKšœ žœ˜šžœ žœžœ˜Kšžœ"žœžœžœ˜SKšžœ˜—Kšœ˜K˜—K˜š   œžœ"žœ žœ žœ žœ˜fKšœžœ˜!šžœ!žœžœž˜2Kšžœžœžœžœ ˜QKšžœ˜—Kšœ˜—K˜š  œžœ žœžœžœžœ˜Ošžœ žœžœ˜KšœB˜BKšžœžœ˜K˜—šžœ žœ˜KšœI˜IKšžœžœ˜K˜—Kšžœžœ˜ Kšœ˜—K™K™%š  œžœ žœžœžœžœžœ žœ žœ˜qKšœ˜Kšœ ˜ K˜Kš žœžœžœžœžœ$˜BKšœžœ˜Kšœ-˜-šžœ!žœžœž˜2Kšžœžœžœ˜*Kšœžœ˜/Kšœ-˜-Kšžœ˜—Kšœ˜—K˜š  œžœžœžœžœžœ˜PKšžœ žœžœ˜)Kšžœ žœžœ˜)Kšžœ˜ K˜—K˜š   œžœžœžœžœžœ˜BKšœ žœ;˜HKšœ žœ;˜HK˜šžœ ˜ Kš žœžœ žœžœžœžœ ˜9Kš žœžœ žœžœ žœžœ˜I—K˜—K˜š  œžœžœžœžœžœ žœ˜PJšœ8˜8Jšœ+žœžœžœ˜jJšœ˜J˜—L™Lšœ™KšœF˜FKšœ?˜?K˜Kšœ‡˜‡Kšœ›˜›Kšœ˜K˜Kšœ8˜8Kšœ4˜4KšœH˜HK˜Kšžœ˜K˜——…—/ΰFΙ