DIRECTORY Ascii, BasicTime, CD, CDBasics, CDCells, CDCommandOps, CDDebug, CDDefaultProcs, CDDirectory, CDEnvironment, CDEvents, CDGenerate, CDInstances, CDIO, CDOps, CDOpsExtras, CDPrivate, CDProperties, CDSequencer, GList, IO, PW, RefTab, Rope, RopeList, TerminalIO, TokenIO; PWImpl: CEDAR PROGRAM IMPORTS Ascii, BasicTime, CD, CDBasics, CDCells, CDCommandOps, CDDebug, CDDefaultProcs, CDDirectory, CDEnvironment, CDEvents, CDGenerate, CDInstances, CDIO, CDOps, CDOpsExtras, CDPrivate, CDProperties, CDSequencer, GList, IO, RefTab, Rope, RopeList, TerminalIO, TokenIO EXPORTS PW SHARES CDDirectory = BEGIN OPEN PW; abutXClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$AbutX, [ quickDrawMe: QuickDrawAbut, drawMe: DrawAbut, internalRead: ReadAbutX, internalWrite: WriteAbut, interestRect: AbutInterestRect ]]; abutYClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$AbutY, [ quickDrawMe: QuickDrawAbut, drawMe: DrawAbut, internalRead: ReadAbutY, internalWrite: WriteAbut, interestRect: AbutInterestRect ]]; AbutSpecific: TYPE = REF AbutSpecificRec; AbutSpecificRec: TYPE = RECORD [ ir: CD.Rect, -- for algorithmic efficiency subObjects: SEQUENCE size: NAT OF CD.Object ]; CreateNewAbutX: PUBLIC CreateAbutProc = { abutSpecific: AbutSpecific _ NEW [AbutSpecificRec[GList.Length[subObjects]]]; new: CD.Object; FOR i: NAT IN [0 .. abutSpecific.size) DO abutSpecific[i] _ subObjects.first; subObjects _ subObjects.rest; ENDLOOP; IF abutSpecific.size#0 THEN { iry: INT = CD.InterestSize[abutSpecific[0]].y; FOR i: NAT IN [1 .. abutSpecific.size) DO IF CD.InterestSize[abutSpecific[i]].y#iry THEN ERROR; -- incompatible y dimension for an abutX ENDLOOP; }; newAbut _ NEW [CD.ObjectRep _ [class: abutXClass, specific: abutSpecific, properties: props]]; new _ ExpandAbut[newAbut].new; newAbut.bbox _ new.bbox; abutSpecific.ir _ CD.InterestRect[new]; SetName[newAbut, name]; }; CreateNewAbutY: PUBLIC CreateAbutProc = { abutSpecific: AbutSpecific _ NEW [AbutSpecificRec[GList.Length[subObjects]]]; new: CD.Object; FOR i: NAT IN [0 .. abutSpecific.size) DO abutSpecific[i] _ subObjects.first; subObjects _ subObjects.rest; ENDLOOP; IF abutSpecific.size#0 THEN { irx: INT = CD.InterestSize[abutSpecific[0]].x; FOR i: NAT IN [1 .. abutSpecific.size) DO IF CD.InterestSize[abutSpecific[i]].x#irx THEN ERROR; -- incompatible x dimension for an abutY ENDLOOP; }; newAbut _ NEW [CD.ObjectRep _ [class: abutYClass, specific: abutSpecific, properties: props]]; new _ ExpandAbut[newAbut].new; newAbut.bbox _ new.bbox; abutSpecific.ir _ CD.InterestRect[new]; SetName[newAbut, name]; }; EnumerateSubObjects: PUBLIC PROC [abut: CD.Object, eachSubObject: EachSubObjectProc] RETURNS [quit: BOOL _ FALSE] = { abutSpecific: AbutSpecific = NARROW [abut.specific]; pos: CD.Position _ [0, 0]; FOR i: NAT IN [0 .. abutSpecific.size) DO quit _ eachSubObject[abutSpecific[i], pos]; IF quit THEN RETURN; SELECT abut.class FROM abutXClass => pos.x _ pos.x + CD.InterestSize[abutSpecific[i]].x; abutYClass => pos.y _ pos.y + CD.InterestSize[abutSpecific[i]].y; ENDCASE => ERROR; ENDLOOP; }; CountSubObjects: PUBLIC PROC [abut: CD.Object] RETURNS [size: NAT] = { abutSpecific: AbutSpecific = NARROW [abut.specific]; size _ abutSpecific.size; }; ExpandAbut: CDDirectory.ExpandProc = { EachSubObject: EachSubObjectProc = { instances _ CONS [CDInstances.NewInst[subObject, [CDBasics.SubPoints[pos, CD.InterestBase[subObject]]]], instances]; }; instances: LIST OF CD.Instance; [] _ EnumerateSubObjects[me, EachSubObject]; new _ CreateCell[instances: instances, name: Name[me]]; IF into#NIL THEN [] _ CDDirectory.Include[into, new, Name[me]]; }; DrawAbut: CD.DrawProc ~ { mapClip: CD.Rect _ CDBasics.DeMapRect[pr.interestClip, trans].itemInCell; EachSubObject: EachSubObjectProc ~ { pos _ CDBasics.SubPoints[pos, CD.InterestBase[subObject]]; IF CDBasics.Intersect[mapClip, CDBasics.MoveRect[subObject.bbox, pos]] THEN pr.drawChild[pr, subObject, [off: CDBasics.MapPoint[pos, trans], orient: trans.orient]]; quit _ pr.stopFlag^; }; [] _ EnumerateSubObjects[ob, EachSubObject]; }; abutSimplification: REAL _ 100.0; -- average size below which things get simplified QuickDrawAbut: CD.DrawProc ~ { mapClip: CD.Rect _ CDBasics.DeMapRect[pr.interestClip, trans].itemInCell; EachSubObject: EachSubObjectProc ~ { pos _ CDBasics.SubPoints[pos, CD.InterestBase[subObject]]; IF CDBasics.Intersect[mapClip, CDBasics.MoveRect[subObject.bbox, pos]] THEN subObject.class.quickDrawMe[pr, subObject, [off: CDBasics.MapPoint[pos, trans], orient: trans.orient]]; quit _ pr.stopFlag^; }; IF DrawObjectOutline[pr, ob, trans, abutSimplification] THEN RETURN; -- object outlined [] _ EnumerateSubObjects[ob, EachSubObject]; }; EnumerateChildObjectsAbut: CDDirectory.EnumerateChildObjectsProc = { EachSubObject: EachSubObjectProc = {quit _ proc[subObject, data]}; quit _ EnumerateSubObjects[me, EachSubObject]; }; ReplaceDirectChildsAbut: CDDirectory.ReplaceDChildsProc = { bbox: CD.Rect _ me.bbox; abutSpecific: AbutSpecific = NARROW [me.specific]; FOR i: NAT IN [0 .. abutSpecific.size) DO element: CD.Object = abutSpecific[i]; FOR l: CDDirectory.ReplaceList _ replace, l.rest WHILE l#NIL DO IF l.first.old=element THEN { IF l.first.trans#[] THEN ERROR; IF (IF me.class=abutXClass THEN CD.InterestSize[element].y#CD.InterestSize[l.first.new].y ELSE CD.InterestSize[element].x#CD.InterestSize[l.first.new].x) THEN ERROR; changed _ TRUE; abutSpecific[i] _ l.first.new; }; ENDLOOP; ENDLOOP; IF NOT changed THEN RETURN; me.bbox _ ExpandAbut[me].new.bbox; changed _ bbox = me.bbox; CDDirectory.PropagateResize[design, me]; }; AbutInterestRect: CD.RectProc = { abutSpecific: AbutSpecific = NARROW [ob.specific]; RETURN [abutSpecific.ir]; }; WriteAbut: CD.InternalWriteProc = { data: AbutSpecific = NARROW [ob.specific]; CDIO.WriteRect[h, ob.bbox]; TokenIO.WriteInt[h, data.size]; CDIO.WriteRect[h, data.ir]; FOR x: NAT IN [0 .. data.size) DO CDIO.WriteObject[h, data[x]] ENDLOOP; }; ReadAbutX: CD.InternalReadProc = { bbox: CD.Rect _ CDIO.ReadRect[h]; size: NAT _ TokenIO.ReadInt[h]; data: AbutSpecific _ NEW [AbutSpecificRec[size]]; ob: CD.Object _ NEW [CD.ObjectRep _ [class: abutXClass, specific: data, bbox: bbox]]; data.ir _ CDIO.ReadRect[h]; FOR x: NAT IN [0 .. size) DO data[x] _ CDIO.ReadObject[h] ENDLOOP; RETURN [ob]; }; ReadAbutY: CD.InternalReadProc = { bbox: CD.Rect _ CDIO.ReadRect[h]; size: NAT _ TokenIO.ReadInt[h]; data: AbutSpecific _ NEW [AbutSpecificRec[size]]; ob: CD.Object _ NEW [CD.ObjectRep _ [class: abutYClass, specific: data, bbox: bbox]]; data.ir _ CDIO.ReadRect[h]; FOR x: NAT IN [0 .. size) DO data[x] _ CDIO.ReadObject[h] ENDLOOP; RETURN [ob]; }; AbutX: PUBLIC PROC [t1, t2, t3, t4, t5, t6: CD.Object _ NIL] RETURNS [obj: CD.Object] = { RETURN [AbutListX[LIST[t1, t2, t3, t4, t5, t6]]]; }; AbutY: PUBLIC PROC [t1, t2, t3, t4, t5, t6: CD.Object _ NIL] RETURNS [obj: CD.Object] = { RETURN [AbutListY[LIST[t1, t2, t3, t4, t5, t6]]]; }; AbutListX: PUBLIC PROC [objects: LIST OF CD.Object, name: Rope.ROPE _ NIL, props: CD.PropList _ NIL] RETURNS [obj: CD.Object] = { newObjects: LIST OF CD.Object _ NIL; WHILE objects#NIL DO IF objects.first#NIL THEN newObjects _ CONS [objects.first, newObjects]; objects _ objects.rest; ENDLOOP; IF newObjects=NIL THEN RETURN [NIL]; obj _ CreateNewAbutX[NARROW [GList.Reverse[newObjects]], name, props]; }; AbutListY: PUBLIC PROC [objects: LIST OF CD.Object, name: Rope.ROPE _ NIL, props: CD.PropList _ NIL] RETURNS [obj: CD.Object] = { newObjects: LIST OF CD.Object _ NIL; WHILE objects#NIL DO IF objects.first#NIL THEN newObjects _ CONS [objects.first, newObjects]; objects _ objects.rest; ENDLOOP; IF newObjects=NIL THEN RETURN [NIL]; obj _ CreateNewAbutY[NARROW [GList.Reverse[newObjects]], name, props]; }; MapFunction: PUBLIC PROC [function: PROC [INT, INT] RETURNS [CD.Object], lx: INT _ 0, ux: INT, ly: INT _ 0, uy: INT] RETURNS [CD.Object] = { rows: LIST OF CD.Object _ NIL; FOR y: INT DECREASING IN [ly .. uy) DO row: LIST OF CD.Object _ NIL; FOR x: INT DECREASING IN [lx .. ux) DO row _ CONS [function[x, y], row] ENDLOOP; rows _ CONS [AbutListX[row], rows]; ENDLOOP; RETURN [AbutListY[rows]]; }; ArrayX: PUBLIC PROC [obj: CD.Object, nx: INT _ 1] RETURNS [CD.Object] = { row: LIST OF CD.Object _ NIL; FOR x: INT IN [0 .. nx) DO row _ CONS [obj, row] ENDLOOP; RETURN [AbutListX[row]]; }; ArrayY: PUBLIC PROC [obj: CD.Object, ny: INT _ 1] RETURNS [CD.Object] = { row: LIST OF CD.Object _ NIL; FOR x: INT IN [0 .. ny) DO row _ CONS [obj, row] ENDLOOP; RETURN [AbutListY[row]]; }; Array: PUBLIC PROC [obj: CD.Object, nx, ny: INT _ 1] RETURNS [new: CD.Object] = { RETURN [ArrayY[ArrayX[obj, nx], ny]]; }; rotationClass: PUBLIC CD.ObjectClass _ RegisterClass[objectType: $Rotation, expand: ExpandRotation, enumerateChildObjects: EnumerateChildObjectsRotation, replaceDirectChilds: ReplaceDirectChildsRotation, interestRect: RotationInterestRect]; CreateRotation: PUBLIC PROC [obj: CD.Object, orientation: CD.Orientation, name: Rope.ROPE _ NIL, props: CD.PropList _ NIL] RETURNS [rotation: CD.Object] = { trans: CD.Transformation = [[0, 0], orientation]; IF obj=NIL THEN RETURN [NIL]; rotation _ NEW [CD.ObjectRep _ [ class: rotationClass, bbox: CDBasics.MapRect[obj.bbox, trans], specific: NEW [RotationSpecificRec _ [ir: CDBasics.MapRect[CD.InterestRect[obj], trans], obj: obj, orientation: orientation]], properties: props ]]; SetName[rotation, name]; }; ExpandRotation: CDDirectory.ExpandProc = { specific: RotationSpecific _ NARROW [me.specific]; new _ CreateCell[ instances: LIST [CDInstances.NewInst[specific.obj, [[0, 0], specific.orientation]]], name: Name[me] ]; }; EnumerateChildObjectsRotation: CDDirectory.EnumerateChildObjectsProc = { specific: RotationSpecific _ NARROW [me.specific]; quit _ proc[specific.obj, data]; }; ReplaceDirectChildsRotation: CDDirectory.ReplaceDChildsProc = { specific: RotationSpecific _ NARROW [me.specific]; bbox: CD.Rect _ me.bbox; FOR l: CDDirectory.ReplaceList _ replace, l.rest WHILE l#NIL DO IF l.first.old=specific.obj THEN { IF l.first.trans#[] THEN ERROR; changed _ TRUE; specific.obj _ l.first.new; }; ENDLOOP; IF ~changed THEN RETURN; me.bbox _ CDBasics.MapRect[specific.obj.bbox, [[0, 0], specific.orientation]]; changed _ bbox = me.bbox; CDDirectory.PropagateResize[design, me]; }; RotationInterestRect: CD.RectProc = { specific: RotationSpecific _ NARROW [ob.specific]; RETURN [specific.ir]; }; indirectClass: PUBLIC CD.ObjectClass _ RegisterClass[objectType: $Indirect, expand: ExpandIndirect, enumerateChildObjects: EnumerateChildObjectsIndirect, replaceDirectChilds: ReplaceDirectChildsIndirect]; CreateIndirect: PUBLIC PROC [sourceObject: CD.Object, name: Rope.ROPE _ NIL, props: CD.PropList _ NIL] RETURNS [indirectObject: CD.Object] = { IF sourceObject=NIL THEN RETURN [NIL]; indirectObject _ NEW [CD.ObjectRep _ [class: indirectClass, bbox: sourceObject.bbox, specific: sourceObject, properties: props]]; SetName[indirectObject, name]; }; ExpandIndirect: CDDirectory.ExpandProc = {new _ NARROW [me.specific]}; EnumerateChildObjectsIndirect: CDDirectory.EnumerateChildObjectsProc = { quit _ proc[NARROW [me.specific], data]; }; ReplaceDirectChildsIndirect: CDDirectory.ReplaceDChildsProc = { indirect: CD.Object = NARROW [me.specific]; bbox: CD.Rect _ me.bbox; FOR l: CDDirectory.ReplaceList _ replace, l.rest WHILE l#NIL DO IF l.first.old=indirect THEN { IF l.first.trans#[] THEN ERROR; changed _ TRUE; me.specific _ l.first.new; }; ENDLOOP; IF ~changed THEN RETURN; me.bbox _ indirect.bbox; changed _ bbox = me.bbox; CDDirectory.PropagateResize[design, me]; }; lazyClass: PUBLIC CD.ObjectClass _ RegisterClass[objectType: $Lazy, expand: ExpandLazy, interestRect: LazyIR]; LazyData: TYPE = REF LazyDataRec; LazyDataRec: TYPE = RECORD [info: REF, createProc: CreateProc, ir: CD.Rect]; CreateLazy: PUBLIC PROC [info: REF, createProc: CreateProc, bbox, ir: CD.Rect, name: Rope.ROPE _ NIL, props: CD.PropList _ NIL] RETURNS [newLazy: CD.Object] = { newLazy _ NEW [CD.ObjectRep _ [ class: lazyClass, specific: NEW [LazyDataRec _ [info: info, createProc: createProc, ir: ir]], properties: props ]]; newLazy.bbox _ bbox; SetName[newLazy, name]; }; LazyIR: CD.RectProc = {lazyData: LazyData _ NARROW [ob.specific]; RETURN [lazyData.ir]}; ExpandLazy: CDDirectory.ExpandProc = { lazyData: LazyData _ NARROW [me.specific]; new _ lazyData.createProc[lazyData.info]; IF CD.InterestRect[new]#lazyData.ir OR new.bbox#me.bbox THEN ERROR; IF into#NIL THEN [] _ CDDirectory.Include[into, new, Name[me]]; }; tilingClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$Tiling, [ quickDrawMe: QuickDrawTiling, drawMe: DrawTiling, internalRead: ReadTiling, internalWrite: WriteTiling, interestRect: TilingInterestRect, description: "tiling object" ]]; TilingData: TYPE = REF TilingDataRec; TilingDataRec: TYPE = RECORD [ ir: CD.Rect, -- interest rect c: SEQUENCE sizeY: NAT OF TileLines -- tiles ]; TileLines: TYPE = REF TileLinesRec; TileLinesRec: TYPE = RECORD [c: SEQUENCE sizeX: NAT OF CD.Object]; CreateTiling: PUBLIC PROC [sizeX, sizeY: NAT, tiles: PROC [x, y: NAT] RETURNS [CD.Object], name: Rope.ROPE _ NIL, props: CD.PropList _ NIL] RETURNS [tiling: CD.Object] = { new: CD.Object; data: TilingData _ NEW [TilingDataRec[sizeY]]; IF sizeX=0 OR sizeY=0 THEN ERROR; FOR y: NAT IN [0 .. sizeY) DO height: INT _ CD.InterestSize[tiles[0, y]].y; FOR x: NAT IN [1 .. sizeX) DO IF CD.InterestSize[tiles[x, y]].y#height THEN ERROR; -- constraint of same height within a row not respected! ENDLOOP; ENDLOOP; FOR x: NAT IN [0 .. sizeX) DO width: INT _ CD.InterestSize[tiles[x, 0]].x; FOR y: NAT IN [1 .. sizeY) DO IF CD.InterestSize[tiles[x, y]].x#width THEN ERROR; -- constraint of same width within a column not respected! ENDLOOP; ENDLOOP; FOR y: NAT IN [0 .. sizeY) DO line: TileLines _ NEW [TileLinesRec[sizeX]]; FOR x: NAT IN [0 .. sizeX) DO line[x] _ tiles[x, y]; ENDLOOP; data[y] _ line; ENDLOOP; tiling _ NEW [CD.ObjectRep _ [class: tilingClass, specific: data, properties: props]]; new _ ExpandTiling[tiling].new; tiling.bbox _ new.bbox; data.ir _ CD.InterestRect[new]; SetName[tiling, name]; }; EnumerateTiles: PUBLIC PROC [tiling: CD.Object, eachTile: EachTileProc] RETURNS [quit: BOOL _ FALSE] = { data: TilingData = NARROW [tiling.specific]; pos: CD.Position _ [0, 0]; FOR y: NAT IN [0 .. data.sizeY) DO line: TileLines _ data[y]; pos.x _ 0; FOR x: NAT IN [0 .. line.sizeX) DO quit _ eachTile[x, y, line[x], pos]; IF quit THEN RETURN; pos.x _ pos.x + CD.InterestSize[line[x]].x; ENDLOOP; pos.y _ pos.y + CD.InterestSize[line[0]].y; ENDLOOP; }; GetTilingSize: PUBLIC PROC [tiling: CD.Object] RETURNS [sizeX, sizeY: NAT] = { data: TilingData = NARROW [tiling.specific]; sizeY _ data.sizeY; sizeX _ data[0].sizeX; }; GetTile: PUBLIC PROC [tiling: CD.Object, x, y: NAT] RETURNS [tile: CD.Object] = { data: TilingData = NARROW [tiling.specific]; tile _ data[y][x]; }; ExpandTiling: CDDirectory.ExpandProc = { EachTile: EachTileProc = { instances _ CONS [CDInstances.NewInst[tile, [CDBasics.SubPoints[pos, CD.InterestBase[tile]]]], instances]; }; instances: LIST OF CD.Instance; [] _ EnumerateTiles[me, EachTile]; new _ CreateCell[instances: instances, name: Name[me]]; IF into#NIL THEN [] _ CDDirectory.Include[into, new, Name[me]]; }; DrawTiling: CD.DrawProc = { mapClip: CD.Rect _ CDBasics.DeMapRect[pr.interestClip, trans].itemInCell; EachTile: EachTileProc = { pos _ CDBasics.SubPoints[pos, CDBasics.BaseOfRect[CD.InterestRect[tile]]]; IF CDBasics.Intersect[mapClip, CDBasics.MoveRect[tile.bbox, pos]] THEN pr.drawChild[pr, tile, [off: CDBasics.MapPoint[pos, trans], orient: trans.orient]]; quit _ pr.stopFlag^; }; [] _ EnumerateTiles[ob, EachTile]; }; tilingSimplification: REAL _ 100.0; -- average size below which things get simplified QuickDrawTiling: CD.DrawProc = { mapClip: CD.Rect _ CDBasics.DeMapRect[pr.interestClip, trans].itemInCell; EachTile: EachTileProc = { pos _ CDBasics.SubPoints[pos, CDBasics.BaseOfRect[CD.InterestRect[tile]]]; IF CDBasics.Intersect[mapClip, CDBasics.MoveRect[tile.bbox, pos]] THEN tile.class.quickDrawMe[pr, tile, [off: CDBasics.MapPoint[pos, trans], orient: trans.orient]]; quit _ pr.stopFlag^; }; IF DrawObjectOutline[pr, ob, trans, tilingSimplification] THEN RETURN; -- object outlined [] _ EnumerateTiles[ob, EachTile]; }; EnumerateTilingChildObjects: CDDirectory.EnumerateChildObjectsProc = { EachTile: EachTileProc = {quit _ proc[tile, data]}; quit _ EnumerateTiles[me, EachTile]; }; ReplaceTilingDirectChilds: CDDirectory.ReplaceDChildsProc = { EachTileCheckNoChange: EachTileProc = { FOR l: CDDirectory.ReplaceList _ replace, l.rest WHILE l#NIL DO quit _ l.first.old=tile; ENDLOOP; }; changed _ EnumerateTiles[me, EachTileCheckNoChange]; IF NOT changed THEN RETURN; ERROR; }; TilingInterestRect: CD.RectProc = { data: TilingData = NARROW [ob.specific]; RETURN [data.ir]; }; WriteTiling: CD.InternalWriteProc = { data: TilingData = NARROW [ob.specific]; CDIO.WriteRect[h, ob.bbox]; TokenIO.WriteInt[h, data[0].sizeX]; TokenIO.WriteInt[h, data.sizeY]; CDIO.WriteRect[h, data.ir]; FOR y: NAT IN [0 .. data.sizeY) DO line: TileLines _ data[y]; FOR x: NAT IN [0 .. line.sizeX) DO CDIO.WriteObject[h, data[y][x]]; ENDLOOP; ENDLOOP; }; ReadTiling: CD.InternalReadProc = { bbox: CD.Rect _ CDIO.ReadRect[h]; sizeX: NAT _ TokenIO.ReadInt[h]; sizeY: NAT _ TokenIO.ReadInt[h]; data: TilingData _ NEW [TilingDataRec[sizeY]]; ob: CD.Object _ NEW [CD.ObjectRep _ [class: tilingClass, specific: data, bbox: bbox]]; data.ir _ CDIO.ReadRect[h]; FOR y: NAT IN [0 .. sizeY) DO line: TileLines _ NEW [TileLinesRec[sizeX]]; FOR x: NAT IN [0 .. sizeX) DO line[x] _ CDIO.ReadObject[h]; ENDLOOP; data[y] _ line; ENDLOOP; RETURN [ob]; }; CreateCell: PUBLIC PROC [instances: CD.InstanceList, ir: CD.Rect _ [0,0,-1,-1], name: Rope.ROPE _ NIL, props: CD.PropList _ NIL] RETURNS [cell: CD.Object]= { cell _ CDCells.CreateCell[il: instances, ir: ir]; cell.properties _ props; CDCells.ToSequenceMode[cell]; SetName[cell, name]; }; SetName: PUBLIC PROC [obj: CD.Object, name: Rope.ROPE] = { CDProperties.PutObjectProp[obj, $Describe, name]; }; Name: PUBLIC PROC [obj: CD.Object] RETURNS [name: Rope.ROPE] = { SearchEachDesign: CDPrivate.DesignEnumerator = { name _ CDDirectory.Name[obj, design]; quit _ name#NIL; }; name _ NARROW [CDProperties.GetObjectProp[obj, $Describe]]; IF name=NIL THEN [] _ CDPrivate.EnumDesigns[SearchEachDesign]; }; Get: PUBLIC PROC [design: CD.Design, name: Rope.ROPE] RETURNS [obj: CD.Object] = { obj _ CDDirectory.Fetch[design, name].object; IF obj=NIL THEN {TerminalIO.PutF["*** Object %g not found in the design.\n", IO.rope[name]]; ERROR}; IF NOT CDOpsExtras.MakeImmutableAndSetNameHints[ob: obj, design: design] THEN TerminalIO.PutF["*** Object %g could not be made immutable.\n", IO.rope[name]]; }; Flatten: PUBLIC PROC [cell: CD.Object] RETURNS [new: CD.Object] = { TopEnumerate: CDCells.InstEnumerator = { obj: CD.Object _ Flatten[inst.ob]; IF NOT CDCells.IsCell[obj] OR CDProperties.GetObjectProp[obj, $DontFlatten]#NIL THEN instances _ CONS [CDInstances.NewInst[obj, inst.trans, CDProperties.DCopyProps[inst.properties]], instances] ELSE { trans: CD.Transformation _ inst.trans; InsideEnumerate: CDCells.InstEnumerator = { instances _ CONS [CDInstances.Composed[inst, trans], instances]; }; [] _ CDCells.EnumerateInstances[obj, InsideEnumerate]; }; }; instances: CD.InstanceList _ NIL; IF CDProperties.GetObjectProp[cell, $DontFlatten]#NIL THEN RETURN [cell]; IF NOT CDCells.IsCell[cell] THEN { new _ CDDirectory.Expand1[cell].new; RETURN [IF new=NIL THEN cell ELSE Flatten[new]]; }; [] _ CDCells.EnumerateInstances[cell, TopEnumerate]; new _ CreateCell[instances: instances, ir: CD.InterestRect[cell], name: Name[cell]]; CDProperties.CopyProps[cell.properties, new]; }; propertiesToFlushOnEdit: LIST OF ATOM _ NIL; childToParents: RefTab.Ref _ RefTab.Create[]; AddChildParent: PROC [child, parent: CD.Object] = { parents: LIST OF CD.Object _ NARROW [RefTab.Fetch[childToParents, child].val]; IF GList.Member[parent, parents] THEN RETURN; parents _ CONS [parent, parents]; [] _ RefTab.Store[childToParents, child, parents]; }; FlushPropertiesAfterReplace: CDEvents.EventProc = { BuildTable: CDDirectory.EachEntryAction = { EachChild: CDDirectory.EachObjectProc = { IF NOT me.immutable THEN AddChildParent[me, ob]; }; sch: Rope.ROPE _ NARROW [CDProperties.GetObjectProp[ob, $IconFor]]; schOb: CD.Object _ IF sch#NIL THEN CDDirectory.Fetch[design, sch].object ELSE NIL; IF schOb#NIL THEN AddChildParent[schOb, ob]; schOb _ IF Rope.Match["*.mask", name] THEN CDDirectory.Fetch[design, Rope.Replace[base: name, start: Rope.Length[name]-4, with: "sch"]].object ELSE NIL; IF schOb#NIL THEN AddChildParent[ob, schOb]; [] _ CDDirectory.EnumerateChildObjects[ob, EachChild]; }; changedObjects: LIST OF CD.Object _ LIST [NARROW [x]]; foundANewOne: BOOL _ TRUE; flushedObjects: Rope.ROPE _ NIL; [] _ CDDirectory.Enumerate[design, BuildTable]; WHILE foundANewOne DO foundANewOne _ FALSE; FOR list: LIST OF CD.Object _ changedObjects, list.rest WHILE list#NIL DO FOR parents: LIST OF CD.Object _ NARROW [RefTab.Fetch[childToParents, list.first].val], parents.rest WHILE parents#NIL DO IF GList.Member[parents.first, changedObjects] THEN LOOP; changedObjects _ CONS [parents.first, changedObjects]; foundANewOne _ TRUE; ENDLOOP; ENDLOOP; ENDLOOP; FOR list: LIST OF CD.Object _ changedObjects, list.rest WHILE list#NIL DO flushed: BOOL _ FALSE; FOR props: LIST OF ATOM _ propertiesToFlushOnEdit, props.rest WHILE props#NIL DO IF CDProperties.GetObjectProp[list.first, props.first]=NIL THEN LOOP; flushed _ TRUE; CDProperties.PutObjectProp[list.first, props.first, NIL]; ENDLOOP; IF flushed THEN flushedObjects _ Rope.Cat[flushedObjects, " ", CDDirectory.Name[list.first, design]]; ENDLOOP; IF flushedObjects#NIL THEN TerminalIO.PutF["Flushed caches for %g.\n ", IO.rope[flushedObjects]]; RefTab.Erase[childToParents]; -- we clean up that table! }; RegisterGenerator: PUBLIC PROC [generator: GeneratorProc, name: Rope.ROPE] = { TerminalIO.PutF["Generator program %g %g.\n", IO.rope[name], IO.rope[ IF CDGenerate.Register[context: CDGenerate.AssertContext["PatchWork"], key: name, generator: generator, cache: FALSE] THEN "recorded" ELSE "overwritten"]]; }; RegisterProp: PUBLIC PROC [prop: ATOM, copy: BOOL _ FALSE, flushOnEdit: BOOL _ FALSE] RETURNS [sameAtom: ATOM] = { [] _ CDProperties.RegisterProperty[prop, $PW]; CDProperties.InstallProcs[prop, [makeCopy: IF copy THEN CDProperties.CopyVal ELSE CDProperties.DontCopy]]; IF flushOnEdit THEN propertiesToFlushOnEdit _ CONS [prop, propertiesToFlushOnEdit]; sameAtom _ prop; }; RegisterClass: PUBLIC PROC [objectType: ATOM, expand: CDDirectory.ExpandProc, enumerateChildObjects: CDDirectory.EnumerateChildObjectsProc _ NIL, replaceDirectChilds: CDDirectory.ReplaceDChildsProc _ NIL, interestRect: CD.RectProc _ NIL, drawMe, quickDrawMe, showMeSelected: CD.DrawProc _ NIL] RETURNS [objectClass: CD.ObjectClass] = { dp: CDDirectory.DirectoryProcs _ [expand: expand]; objectClassRec: CD.ObjectClassRec _ []; objectClassRec.interestRect _ IF interestRect=NIL THEN CDDefaultProcs.InterestRectWithExpand ELSE interestRect; objectClassRec.drawMe _ IF drawMe=NIL THEN CDDefaultProcs.DrawMe ELSE drawMe; objectClassRec.quickDrawMe _ IF quickDrawMe=NIL THEN CDDefaultProcs.QuickDrawMe ELSE quickDrawMe; objectClassRec.showMeSelected _ IF showMeSelected=NIL THEN CDDefaultProcs.ShowMeSelectedWithExpand ELSE showMeSelected; objectClassRec.directoryProcs _ NIL; objectClassRec.xDesign _ FALSE; IF enumerateChildObjects#NIL THEN dp.enumerateChildObjects _ enumerateChildObjects; IF replaceDirectChilds#NIL THEN dp.replaceDirectChilds _ replaceDirectChilds; objectClass _ CD.RegisterObjectClass[objectType, objectClassRec ! CD.Error => CONTINUE]; IF objectClass=NIL THEN objectClass _ CD.FetchObjectClass[objectType]; objectClass.directoryProcs _ CDDirectory.InstallDirectoryProcs[objectClass, dp ! CD.Error => CONTINUE]; }; DrawObjectOutline: PROC [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation, factor: REAL] RETURNS [simplified: BOOL] ~ { averageSize: INT = MAX [((ob.bbox.y2-ob.bbox.y1)+(ob.bbox.x2-ob.bbox.x1))/2, 1]; IF pr.stopFlag^ THEN RETURN [simplified: TRUE]; -- no drawing anyway... simplified _ pr.scaleHint<(factor/averageSize) AND pr.scaleHint>0; IF simplified THEN { -- we do the painting here realIR: CD.Rect = CDBasics.MapRect[CD.InterestRect[ob], trans]; -- remapped interest rect pr.drawOutLine[pr, realIR, CD.outlineLayer]; IF pr.scaleHint*averageSize>9 THEN { -- also paint name inside name: Rope.ROPE _ CDDirectory.Name[ob, pr.design]; IF name=NIL THEN name _ NARROW [CDProperties.GetObjectProp[ob, $Describe]]; IF name#NIL THEN pr.drawComment[pr, realIR, name]; }; }; }; OpenDesign: PUBLIC PROC [fileName: Rope.ROPE] RETURNS [design: CD.Design] = { design _ CDIO.ReadDesign[fileName, NIL, CDIO.GetWorkingDirectory[]]; }; Draw: PUBLIC PROC [obj: CD.Object, technologyName: ATOM _ NIL] RETURNS [design: CD.Design] = { design _ CDDebug.Draw[obj, IF technologyName=NIL THEN $cmosB ELSE technologyName].dummyDesign; design.mutability _ editable; }; RunGenerator: PROC [comm: CDSequencer.Command] = { inner: PROC = { design: CD.Design _ comm.design; pos: CD.Position _ comm.pos; context: CDGenerate.Context _ CDGenerate.AssertContext["PatchWork"]; key: Rope.ROPE; obj: CD.Object; time: BasicTime.GMT _ BasicTime.Now[]; -- Start the stop watch min, sec: INT; TerminalIO.PutF["PatchWork menu selected\n"]; key _ CDGenerate.SelectOneOf[context, "select generate"]; IF Rope.IsEmpty[key] THEN {TerminalIO.PutF["no generator selected\n"]; RETURN}; obj _ CDGenerate.FetchNCall[context, design, key]; sec _ BasicTime.Period[time, BasicTime.Now[]]; min _ sec/60; sec _ sec MOD 60; TerminalIO.PutF["PW completed in "]; IF min#0 THEN TerminalIO.PutF["%g min ", IO.int[min]]; TerminalIO.PutF["%g sec\n", IO.int[sec]]; IF obj=NIL THEN {TerminalIO.PutF["No returned object\n"]; RETURN}; [] _ CDOps.IncludeObjectI[design, obj, pos]; }; CDEnvironment.DoWithWDir[CDEnvironment.GetWorkingDirectory[comm.design], inner]; }; ListIcons: PROC [comm: CDSequencer.Command] = { EachEntry: CDDirectory.EachEntryAction = { count _ count+1; IF NOT Rope.Match["*.icon", name, FALSE] THEN RETURN; IF NOT Ascii.Letter[Rope.Fetch[name]] AND NOT Ascii.Digit[Rope.Fetch[name]] THEN RETURN; displayed _ displayed+1; list _ CONS [name, list]; }; list: LIST OF Rope.ROPE _ NIL; count: INT _ 0; displayed: INT _ 0; TerminalIO.PutF["List icons\n"]; [] _ CDDirectory.Enumerate[comm.design, EachEntry]; list _ RopeList.Sort[list, RopeList.Compare]; FOR l: LIST OF Rope.ROPE _ list, l.rest WHILE l#NIL DO TerminalIO.PutF[" %g", IO.rope[l.first]]; ENDLOOP; TerminalIO.PutF["\n %g objects counted %g displayed\n", IO.int[count], IO.int[displayed]]; }; CDSequencer.ImplementCommand[$PatchWork, RunGenerator]; CDCommandOps.RegisterWithMenu[$RectProgramMenu, "PatchWork generator", "proposes a menu of generators", $PatchWork]; CDEvents.RegisterEventProc[$AfterCellReplacement, FlushPropertiesAfterReplace]; [] _ RegisterProp[$DontFlatten, TRUE]; [] _ RegisterProp[$PWName, TRUE]; CDCommandOps.RegisterWithMenu[$DirectoryMenu, "list icons", "lists cells of the form *.icon", NIL, ListIcons, dontQueue]; [] _ CDDirectory.InstallDirectoryProcs[abutXClass, [ enumerateChildObjects: EnumerateChildObjectsAbut, replaceDirectChilds: ReplaceDirectChildsAbut, expand: ExpandAbut ]]; [] _ CDDirectory.InstallDirectoryProcs[abutYClass, [ enumerateChildObjects: EnumerateChildObjectsAbut, replaceDirectChilds: ReplaceDirectChildsAbut, expand: ExpandAbut ]]; [] _ CDDirectory.InstallDirectoryProcs[tilingClass, [ enumerateChildObjects: EnumerateTilingChildObjects, replaceDirectChilds: ReplaceTilingDirectChilds, expand: ExpandTiling ]]; END. ΠPWImpl.mesa Copyright Σ 1985, 1987 by Xerox Corporation. All rights reserved. Created by: Monier, June 24, 1985 4:30:52 pm PDT Louis Monier August 22, 1985 12:39:11 pm PDT Bertrand Serlet April 24, 1988 11:14:47 pm PDT Don Curry September 11, 1987 6:53:38 pm PDT Jean-Marc Frailong November 3, 1987 2:29:38 pm PST Abuts Takes an abut and returns the cell which is equivalent to this abut. Cell resulting always belongs to the from design if me belongs to the from design. It is included in the to design if to#NIL clipping boundary in object coordinates clipping boundary in object coordinates Abuts: Sugared Rotations Indirect In the future, add an IR proc, and maybe a Draw Proc? Lazy Tilings Implementation detail: we could have one sequence instead of a sequence of sequence, it would be simpler. But it would allow only a limited number of tiles, while this raises the limit. Once Cedar changes, this can be changed! Checking all right Building the array! clipping boundary in object coordinates clipping boundary in object coordinates Implementors goodies Mechanism for flushing during edits Having a RefTab (of the right size) helps avoiding frequent allocations. we include icons of sch In case obj is a mask, the corresponding sch (if any) "depends" on it. That's a hack! We add all the children Slightly wrong here, because we miss the objects which are NOT in the directory (e.g. unnamed cells) If the object may be simplified (small average size), display bbox and name if available and return TRUE, otherwise do nothing & return FALSE. Factor is 50.0 for cells. Making it larger makes it harder to detail a class of objects. This is for the use of Quick DrawProcs, in order to have a standardized clipping algorithm The algorithm mimics the one implemented by CDCellsImpl Utilities for debug Commands -- Generate the object -- Now figure out how long it took to generate this wonderful piece of layout Silly line, just because CD does not do the right thing! Initialization Κ&Τ˜– "Cedar" stylešœ ™ JšœB™BJšœ-Οk™0Icodešœ)™,Kšœ.™.K™+K™2J˜—š ˜ Jšœ˜Jšœ{œ;˜ΌJšœœ˜ Jšœ˜Jšœ˜Jšœ˜—J˜šΟnœœ˜Jšœœ{œCœ-˜Jšœ˜ Jšœ˜Jšœœœ˜—head™šœ œœœ˜DKšœ˜Kšœ˜Kšœ˜Kšœ˜Jšœ˜Jšœ˜J™—šœ œœœ˜DKšœ˜Kšœ˜Kšœ˜Kšœ˜Jšœ˜Jšœ˜J˜—Jšœœœ˜)šœœœ˜ Jšœœ Οc˜,Jš œ œœœœ˜+J˜J˜—šΠbnœœ˜)Jšœœ-˜MJšœœ˜šœœœ˜)JšœA˜AJšœ˜—šœœ˜Jšœœœ!˜.šœœœ˜)Jš œœ%œœŸ(˜^Jšœ˜—J˜—Jšœ œœM˜^Jšœ˜Jšœ˜Jšœœ˜'Jšœ˜Jšœ˜J˜—š œœ˜)Jšœœ-˜MJšœœ˜šœœœ˜)JšœA˜AJšœ˜—šœœ˜Jšœœœ!˜.šœœœ˜)Jš œœ%œœŸ(˜^Jšœ˜—J˜—Jšœ œœM˜^Jšœ˜Jšœ˜Jšœœ˜'Jšœ˜Jšœ˜J˜—šžœœœœ+œœœ˜uJšœœ˜4Kšœœ˜šœœœ˜)Jšœ+˜+Jšœœœ˜šœ ˜Jšœœ!˜BJšœœ!˜BJšœœ˜—Jšœ˜—K˜K˜—š žœœœœ œœ˜FJšœœ˜4Jšœ˜J˜K˜—JšœΎ™Α•StartOfExpansionI -- [me: CD.ObPtr, from: CD.Design, to: CD.Design] RETURNS [CD.ObPtr] -- šž œ˜&šž œ˜$Kšœ œ:œ(˜tK˜—Kšœ œœœ ˜Jšœ,˜,Jšœ8˜8Jšœœœ/˜?J˜J˜—šžœœ ˜šœ œ?˜JKšœ'™'—šž œ˜$Kšœœ˜:šœD˜FKšœY˜]—Kšœœ ˜K˜—Jšœ,˜,K˜K˜—šœœ Ÿ1˜SK˜—šž œœ ˜šœ œ?˜JKšœ'™'—šž œ˜$Kšœœ˜:šœD˜FKšœh˜l—Kšœ˜K˜—Kšœ6œœŸ˜WJšœ,˜,K˜K˜—šžœ+˜DKšž œ5˜BJšœ.˜.Jšœ˜J˜—–k -- [me: CD.ObPtr, design: CD.Design, replace: CDDirectory.ReplaceList] RETURNS [changed: BOOL _ FALSE] -- šžœ$˜;Jšœœ˜Jšœœ˜2šœœœ˜)Jšœ œ˜%šœ.œœ˜?šœœ˜Jšœœœ˜Jšœœœœœœœœœœ˜₯Jšœ œ˜Jšœ˜J˜—Jšœ˜—Jšœ˜—Jšœœ œœ˜Jšœ"˜"Jšœ˜Jšœ(˜(Jšœ˜J˜—–G -- [me: CD.ObPtr, p: CDDirectory.EnumerateObjectsProc, x: REF ANY] -- šžœœ ˜!Jšœœ˜2Jšœ˜J˜J˜—š  œœ˜#Jšœœ˜*Kšœ˜Kšœ˜Kšœ˜Kš œœœœœœ˜GK˜K˜—šž œœ˜"Kšœœœ˜"Kšœœ˜Kšœœ˜1Kšœœ œœ>˜UKšœ œ ˜Kš œœœ œ œœ˜BKšœ˜ K˜K˜—šž œœ˜"Kšœœœ˜"Kšœœ˜Kšœœ˜1Kšœœ œœ>˜UKšœ œ ˜Kš œœœ œ œœ˜BKšœ˜ K˜——šžœ ™šžœœœœ œœœ ˜YJšœ œ˜1Jšœ˜J˜—šžœœœœ œœœ ˜YJšœ œ˜1Jšœ˜J˜—šž œœœ œœœœœ œ œœœ ˜Jš œ œœœ œ˜$šœ œ˜Jšœœœœ˜HJšœ˜Jšœ˜—Jš œ œœœœ˜$Jšœœ+˜FJšœ˜J˜—šž œœœ œœœœœ œ œœœ ˜Jš œ œœœ œ˜$šœ œ˜Jšœœœœ˜HJšœ˜Jšœ˜—Jš œ œœœœ˜$Jšœœ+˜FJšœ˜J˜—šž œœœ œœœœœœ œœ œœœ ˜ŒJš œœœœ œ˜š œœ œœ ˜&Jš œœœœ œ˜Jšœœ œœ œœœ˜PJšœœ˜#Jšœ˜—Jšœ˜Jšœ˜J˜—šžœœœœ œœœ ˜IJš œœœœ œ˜Jš œœœ œœ œ˜9Jšœ˜Jšœ˜J˜—šžœœœœ œœœ ˜IJš œœœœ œ˜Jš œœœ œœ œ˜9Jšœ˜Jšœ˜J˜—šžœœœœœœœ ˜QJšœ˜%Jšœ˜——šœ ™ šœœœΨ˜πJ˜—šžœœœœœœœ œ œœ œ ˜œJšœœ(˜1Jš œœœœœ˜šœ œœ˜ Jšœ˜Jšœ)˜)Jšœ œ.œA˜~J˜Jšœ˜—Jšœ˜Jšœ˜J˜—–I -- [me: CD.ObPtr, from: CD.Design, to: CD.Design] RETURNS [CD.ObPtr] -- šžœ˜*Jšœœ˜2šœ˜Jšœ œF˜UJšœ˜Jšœ˜—Jšœ˜J˜—šžœ+˜HJšœœ˜2Jšœ ˜ Jšœ˜J˜—–k -- [me: CD.ObPtr, design: CD.Design, replace: CDDirectory.ReplaceList] RETURNS [changed: BOOL _ FALSE] -- šžœ$˜?Jšœœ˜2Jšœœ˜šœ.œœ˜?šœœ˜"Jšœœœ˜Jšœ œ˜,Jšœ˜—Jšœ˜—Jšœ œœ˜JšœN˜NJšœ˜Jšœ(˜(Jšœ˜J˜—–G -- [me: CD.ObPtr, p: CDDirectory.EnumerateObjectsProc, x: REF ANY] -- šžœœ ˜%Jšœœ˜2Jšœ˜J˜——™šœœœ΄˜ΜJšœœ™5J˜—šžœœœœœœ œ œœœ ˜ŽJš œœœœœ˜&Jšœœœi˜Jšœ˜Jšœ˜J˜—–I -- [me: CD.ObPtr, from: CD.Design, to: CD.Design] RETURNS [CD.ObPtr] -- šžœ"œ˜FJ˜—šžœ+˜HJšœ œ˜(Jšœ˜J˜—–k -- [me: CD.ObPtr, design: CD.Design, replace: CDDirectory.ReplaceList] RETURNS [changed: BOOL _ FALSE] -- šžœ$˜?Jšœ œ œ˜+Jšœœ˜šœ.œœ˜?šœœ˜Jšœœœ˜Jšœ œ˜+Jšœ˜—Jšœ˜—Jšœ œœ˜Jšœ˜Jšœ˜Jšœ(˜(Jšœ˜——™šœ œœZ˜nJ˜—JšΟbœœœ ˜!š œ œœœœ˜LJ˜—šž œœœœ$œœœ œ œœ œ ˜ šœ œœ˜Jšœ˜Jšœ œ?˜LJšœ˜Jšœ˜—Jšœ˜Jšœ˜Jšœ˜J˜—–I -- [me: CD.ObPtr, from: CD.Design, to: CD.Design] RETURNS [CD.ObPtr] -- šžœœ"œœ˜XJ˜—šž œ˜&Jšœœ˜*Jšœ)˜)Jš œœœœœ˜CJšœœœ/˜?J˜——™šœ œœœ˜FKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ!˜!K˜Kšœ˜K˜—Kšœ œœ˜%šœœœ˜Kšœœ Ÿ˜ Kšœœœœ Ÿ˜-Kšœ˜—Kšœδ™δKšœ œœ˜#š œœœœœœœ ˜BK˜—šž œœœœ œœœœœœ œ œœ œ ˜«Jšœœ˜Kšœœ˜.Kšœ™Kšœ œ œœ˜!šœœœ˜Jšœœœ˜-šœœœ˜Jš œœ$œœŸ8˜mKšœ˜—Kšœ˜—šœœœ˜Jšœœœ˜,šœœœ˜Jš œœ#œœŸ:˜nKšœ˜—Kšœ˜—Kšœ™šœœœ˜Kšœœ˜,šœœœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ˜—Jšœ œœF˜VJšœ˜Jšœ˜Jšœ œ˜Jšœ˜K˜K˜—šžœœœ œ!œœœ˜hJšœœ˜,Kšœœ˜šœœœ˜"Kšœ˜Kšœ ˜ šœœœ˜"Jšœ$˜$Jšœœœ˜Jšœœ˜+Kšœ˜—Jšœœ˜+Kšœ˜—K˜K˜—š ž œœœ œ œœ˜NJšœœ˜,Jšœ˜Jšœ˜K˜—šžœœœ œœœœ ˜QJšœœ˜,Kšœ˜K˜K˜—–I -- [me: CD.ObPtr, from: CD.Design, to: CD.Design] RETURNS [CD.ObPtr] -- šž œ˜(šžœ˜Kšœ œ5œ#˜jK˜—Kšœ œœœ ˜Jšœ"˜"Jšœ8˜8Jšœœœ/˜?J˜J˜—šž œœ ˜šœ œ?˜JKšœ'™'—šžœ˜Kšœ2œ˜Jšœ@˜BKšœT˜X—Kšœœ ˜K˜—Jšœ"˜"Kšœ˜K˜—šœœ Ÿ1˜UK˜—šžœœ ˜ šœ œ?˜JKšœ'™'—šžœ˜Kšœ2œ˜Jšœ@˜BKšœ^˜b—Kšœ˜K˜—Kšœ8œœŸ˜YJšœ"˜"Kšœ˜K˜—šžœ+˜FKšžœ+˜3Jšœ$˜$Jšœ˜J˜—–k -- [me: CD.ObPtr, design: CD.Design, replace: CDDirectory.ReplaceList] RETURNS [changed: BOOL _ FALSE] -- šžœ$˜=šžœ˜'šœ.œœ˜?Jšœ˜Jšœ˜—Kšœ˜—Jšœ4˜4Jšœœ œœ˜Jšœ˜Jšœ˜J˜—–G -- [me: CD.ObPtr, p: CDDirectory.EnumerateObjectsProc, x: REF ANY] -- šžœœ ˜#Jšœœ˜(Jšœ ˜J˜K˜—šž œœ˜%Jšœœ˜(Kšœ˜Kšœ#˜#Kšœ ˜ Kšœ˜šœœœ˜"Kšœ˜šœœœ˜"Kšœ˜ Kšœ˜—Kšœ˜—K˜K˜—šž œœ˜#Kšœœœ˜"Kšœœ˜ Kšœœ˜ Kšœœ˜.Kšœœ œœ?˜VKšœ œ ˜šœœœ˜Kšœœ˜,šœœœ˜Kšœ œ˜Kšœ˜—K˜Kšœ˜—Kšœ˜ K˜——™šž œœœ œœ œœ œ œœœ ˜Jšœ1˜1Jšœ˜Jšœ˜Jšœ˜J˜J˜—š žœœœœœ˜:Jšœ1˜1J˜J˜—š žœœœœ œ œ˜@šžœ ˜0Jšœ%˜%Jšœ œ˜J˜—Jšœœ.˜;Jšœœœ.˜>J˜K˜—šžœœœ œœœœ ˜RKšœ-˜-Kš œœœ>œœ˜dKšœœCœAœ ˜K˜K˜—š žœœœœ œœ ˜Cšž œ˜(Jšœœ˜"šœœœ/˜OJšœ œ\˜qšœ˜Jšœœ˜&šžœ˜+Jšœ œ0˜@J˜—Jšœ6˜6—J˜—J˜J˜—Jšœ œœ˜!Jšœ0œœœ˜Išœœœ˜"Jšœ%˜%Jš œœœœœ˜0Jšœ˜—Jšœ4˜4Jšœ+œ'˜TJšœ-˜-Jšœ˜J˜—Jšœ#™#Jš œœœœœ˜,šœ-˜-JšœH™HJ™—–< -- [name: ROPE, ob: CD.Object] RETURNS [quit: BOOL _ FALSE]šžœœœ ˜3Jš œ œœœ œ+˜NJšœœœ˜-Jšœ œ˜!Jšœ2˜2J˜J˜—šžœ˜3šž œ!˜+šž œ ˜)Jšœœœ˜0Jšœ˜—Jšœ œœ,˜CJš œœ œœœ'œœ˜RJšœ™Jšœœœ˜,JšœV™VJš œœœeœœ˜˜Jšœœœ˜,Jšœ™Jšœ6˜6Jšœ˜—Jš œœœœ œœ˜6J–< -- [name: ROPE, ob: CD.Object] RETURNS [quit: BOOL _ FALSE]šœœœ˜Jšœœœ˜ Jšœ;œ&™dJšœ0˜0šœœ˜Jšœœ˜š œœœœ$œœ˜Išœ œœœ œ>œ œ˜yJšœ-œœ˜9Jšœœ1œ˜KJšœ˜—Jšœ˜—Jšœ˜—š œœœœ$œœ˜IJšœ œœ˜š œœœœ'œœ˜PJšœ5œœœ˜EJšœ œ˜Jšœ4œ˜:Jšœ˜—Jšœ œV˜eJšœ˜—Jšœœœ.œ˜aJšœŸ˜8Jšœ˜J˜—šžœœœ'œ˜Nšœ.œ œ˜EJšœmœœ œ˜›—Jšœ˜J˜—šž œœœœœœœœœ œ˜rJšœ.˜.Jšœ+œœœ˜jJšœ œœ!˜SJšœ˜J˜J˜—šž œœœœaœ8œœ œ'œ œœœ˜ΟKšœ2˜2Kšœœ˜'Jš œœœœ'œ˜oJš œœœœœ˜MJš œœ œœœ ˜aJš œ œœœ)œ˜wKšœ œœ˜DKšœœœ2˜SKšœœœ.˜MKšœœ2œ œ˜XKšœ œœœ˜FKšœQœ œ˜gK˜K˜—šžœœœœœœœœ˜~Kšœdœ œ™ŽK™XKšœZ™ZK™7Kšœ œœ:˜PKš œœœœŸ˜GKšœ/œ˜Bšœ œŸ˜/KšœœœŸ˜YKšœœ˜,šœœŸ˜>Kšœ œ#˜2Kšœœœœ-˜KKšœœœ"˜2Kšœ˜—Kšœ˜—K˜——šœ™š ž œœœœœ œ ˜MJšœ œœœ˜DJšœ˜J™—šžœœœœœœœ œ ˜^Kš œœœœœ˜^Kšœ˜K˜——šœ™šž œœ ˜2šœœ˜Jšœœ˜ Jšœœ˜JšœD˜DJšœ œ˜Jšœœ˜JšœœŸ˜>Jšœ œ˜Jšœ-˜-Jšœ:˜:Jšœœ.œ˜OJšŸ™Jšœ2˜2JšŸM™MJšœ.˜.Jšœœ˜Jšœ$˜$Jšœœœ(œ ˜`Jšœœœ+œ˜BJšœ,˜,J˜—Jšœœ™8JšœP˜PJšœ˜J˜—šž œœ ˜/š  œ!˜*Kšœ˜Kš œœœœœ˜5Kš œœ œœœœ˜XKšœ˜Kšœœ˜Kšœ˜K˜—Kš œœœœœ œœ˜BKšœ ˜ Kšœ3˜3Kšœ-˜-š œœœœœœ˜6Kšœœ˜*Kšœ˜—Kšœ:œ œ˜\Kšœ˜——šœ™Jšœ7˜7Jšœu˜uJšœO˜OJšœ œ˜&Jšœœ˜!Kšœ^œ˜yšœ4˜4Kšœr˜rKšœ˜—šœ4˜4Kšœr˜rKšœ˜—šœ5˜5Kšœx˜xKšœ˜—J˜—Jšœ˜—…—ll›