<> <> <> <> DIRECTORY CD, CDInstances, CDBasics, CDCells, CDLayers USING [MakeAbstract, AbstractToPaint], CDImports, CDIO, CDOps, CDSymbolicObjects, CDPrivate, CDProperties, CDRects, Imager, ImagerPath, LRUCache, Rope; CDSymbolicObjectsImpl: CEDAR MONITOR IMPORTS CD, CDInstances, CDBasics, CDCells, CDLayers, CDIO, CDOps, CDPrivate, CDProperties, CDRects, Imager, ImagerPath, LRUCache, Rope EXPORTS CDSymbolicObjects SHARES CDLayers = BEGIN symNameProp: ATOM = $SignalName; symLayerProp: ATOM = $layerOfPin; symOwnerProp: ATOM = $ownerOfPin; markObject: CD.Object; markObjectPath: ImagerPath.Trajectory = CreateMarkObjectPath[]; dummySpecific: REF SymRec = NEW[SymRec]; SymRec: TYPE = RECORD [dummy: INT _ 17]; pinLayer: PUBLIC CD.Layer _ CD.NewLayer[NIL, $pinRepresentation]; segmentLayer: PUBLIC CD.Layer _ CD.NewLayer[NIL, $segmentRepresentation]; markLayer: CD.Layer _ pinLayer; lruQueue: LRUCache.Handle _ LRUCache.Create[87, CDPrivate.Hash, Equal]; freePin: CD.Object _ NIL; --reduces the allocators work freeSegment: CD.Object _ NIL; GivePin: ENTRY PROC [] RETURNS [ob: CD.Object] = INLINE { ob _ freePin; freePin _ NIL; IF ob=NIL THEN ob _ NEW[CD.ObjectRep_[class: pinClass, specific: dummySpecific, layer: pinLayer, immutable: TRUE]]; }; GiveSegment: ENTRY PROC [] RETURNS [ob: CD.Object] = INLINE { ob _ freeSegment; freeSegment _ NIL; IF ob=NIL THEN ob _ NEW[CD.ObjectRep_[class: segmentClass, specific: dummySpecific, layer: segmentLayer, immutable: TRUE]]; }; Equal: PROC[x, y: REF] RETURNS [BOOL] = { ob1: CD.Object = NARROW[x]; ob2: CD.Object = NARROW[y]; RETURN [ob1.class=ob2.class AND ob1.bbox=ob2.bbox AND ob1.layer=ob2.layer] }; pinClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$PinOb0, [ drawMe: DrawPin, quickDrawMe: DrawPin, showMeSelected: ShowSelectedSymRL, internalRead: ReadPin, internalWrite: WritePinOrSegment, wireTyped: TRUE, symbolic: TRUE, description: "pin", describe: Describe, newLayer: ChangePinLayer ]]; segmentClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$SymbolicSegment, [ drawMe: DrawSegment, quickDrawMe: DrawSegment, showMeSelected: ShowSelectedSymRL, internalRead: ReadSegment, internalWrite: WritePinOrSegment, wireTyped: TRUE, symbolic: TRUE, description: "segment", describe: Describe, newLayer: ChangePinLayer ]]; markClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$AlignmentMarkOb, [ drawMe: DrawMark, quickDrawMe: DrawMark, internalRead: ReadMark, internalWrite: WriteMark, symbolic: TRUE, description: "mark", newLayer: ChangePinLayer ]]; CreateMarkObjectPath: PROC [] RETURNS [markObjectPath: ImagerPath.Trajectory] = { markObjectPath _ ImagerPath.MoveTo[[0, 0]]; markObjectPath _ ImagerPath.LineTo[markObjectPath, [0, 3]]; markObjectPath _ ImagerPath.LineTo[markObjectPath, [1, 2]]; markObjectPath _ ImagerPath.LineTo[markObjectPath, [3, 4]]; markObjectPath _ ImagerPath.LineTo[markObjectPath, [4, 3]]; markObjectPath _ ImagerPath.LineTo[markObjectPath, [2, 1]]; markObjectPath _ ImagerPath.LineTo[markObjectPath, [3, 0]]; markObjectPath _ ImagerPath.LineTo[markObjectPath, [0, 0]]; }; Init: PROC [] = { <<--rects>> CDLayers.MakeAbstract[pinLayer]; CDRects.UseForCreateRect[pinLayer, RCreatePin, pinClass]; <<--lines>> CDLayers.MakeAbstract[segmentLayer]; CDRects.UseForCreateRect[segmentLayer, RCreateSegment, segmentClass]; <<--points>> markObject _ NEW[CD.ObjectRep _ [ class: markClass, bbox: [0, 0, 4, 4], layer: markLayer, immutable: TRUE, specific: $AlignmentMarkOb ]]; <<--common>> [] _ CDProperties.RegisterProperty[symLayerProp, $layer]; [] _ CDProperties.RegisterProperty[symOwnerProp, $atom]; CDProperties.InstallProcs[prop: symOwnerProp, procs: [makeCopy: CDProperties.CopyVal]]; CDProperties.InstallProcs[prop: symLayerProp, procs: [makeCopy: CDProperties.CopyVal]]; }; CreateMark: PUBLIC PROC [dummySize: CD.Number_0] RETURNS [CD.Object] = { RETURN [markObject] }; CreateSegment: PUBLIC PROC [length: CD.Number, dummyWidth: CD.Number_0] RETURNS [ob: CD.Object] = { used: REF; insert: BOOL; ob _ GiveSegment[]; IF dummyWidth<=0 THEN dummyWidth _ 8; ob.bbox _ CDPrivate.MinBBox[[dummyWidth, length]]; [insert: insert, used: used] _ LRUCache.Include[lruQueue, ob]; IF ~insert THEN { freeSegment _ ob; ob _ NARROW[used]; }; }; RCreateSegment: PROC [size: CD.Position, l: CD.Layer] RETURNS [CD.Object] = { RETURN [CreateSegment[size.y, size.x]] }; CreatePin: PUBLIC PROC [size: CD.Position] RETURNS [ob: CD.Object] = { used: REF; insert: BOOL; ob _ GivePin[]; ob.bbox _ CDPrivate.MinBBox[size]; [insert: insert, used: used] _ LRUCache.Include[lruQueue, ob]; IF ~insert THEN {freePin _ ob; ob _ NARROW[used]}; }; RCreatePin: PROC [size: CD.Position, l: CD.Layer] RETURNS [CD.Object] = { <<--has the right form for CDRects type>> RETURN [CreatePin[size]] }; IsSymbolicOb: PUBLIC PROC [ob: CD.Object] RETURNS [BOOL] = { RETURN [ob.class=markClass OR ob.class=segmentClass OR ob.class=pinClass] }; IsMark: PUBLIC PROC [ob: CD.Object] RETURNS [BOOL] = { RETURN [ob.class=markClass] }; IsSegment: PUBLIC PROC [ob: CD.Object] RETURNS [BOOL] = { RETURN [ob.class=segmentClass] }; IsPin: PUBLIC PROC [ob: CD.Object] RETURNS [BOOL] = { RETURN [ob.class=pinClass] }; SymbolicKind: PUBLIC PROC [ob: CD.Object] RETURNS [k: CDSymbolicObjects.Kind] = { SELECT TRUE FROM ob.class=pinClass => k _ pin; ob.class=segmentClass => k _ segment; ob.class=markClass => k _ mark; ENDCASE => k _ notSymbolic }; SetOwner: PUBLIC PROC [symInst: CD.Instance, owner: ATOM_NIL] = { IF IsSymbolicOb[symInst.ob] THEN CDProperties.PutInstanceProp[symInst, symOwnerProp, owner] }; GetOwner: PUBLIC PROC [symInst: CD.Instance] RETURNS [at: ATOM] = { WITH CDProperties.GetInstanceProp[symInst, symOwnerProp] SELECT FROM a: ATOM => at _ a ENDCASE => at _ NIL }; SetName: PUBLIC PROC [symInst: CD.Instance, name: Rope.ROPE] = { IF IsSymbolicOb[symInst.ob] THEN CDProperties.PutInstanceProp[symInst, symNameProp, name] }; GetN: PROC [pl: CD.PropList] RETURNS [r: Rope.ROPE _ NIL] = INLINE { WITH CDProperties.GetListProp[pl, symNameProp] SELECT FROM n: Rope.ROPE => r _ n; rt: REF READONLY TEXT => r _ Rope.FromRefText[rt]; ENDCASE => NULL; }; GetName: PUBLIC PROC [symInst: CD.Instance] RETURNS [r: Rope.ROPE _ NIL] = { RETURN [GetN[symInst.properties]] }; SetLayer: PUBLIC PROC [symInst: CD.Instance, layer: CD.Layer] = { IF IsSymbolicOb[symInst.ob] THEN CDProperties.PutInstanceProp[symInst, symLayerProp, CDPrivate.layers[layer]] }; GetL: PROC [pl: CD.PropList] RETURNS [layer: CD.Layer] = INLINE { WITH CDProperties.GetListProp[pl, symLayerProp] SELECT FROM lp: CDPrivate.LayerRef => layer _ lp^.number ENDCASE => layer _ CD.undefLayer }; GetLayer: PUBLIC PROC [symInst: CD.Instance] RETURNS [layer: CD.Layer] = { RETURN [GetL[symInst.properties]] }; DirectionFromOrient: PUBLIC PROC [o: CD.Orientation] RETURNS [dir: CDSymbolicObjects.Direction] = { SELECT o FROM original, rotate180X => dir _ west; rotate90, rotate90X => dir _ south; rotate180, mirrorX => dir _ east; rotate270, rotate270X => dir _ north; ENDCASE => ERROR; }; OrientFromDirection: PUBLIC PROC [dir: CDSymbolicObjects.Direction] RETURNS [o: CD.Orientation] = { SELECT dir FROM west => o _ original; south => o _ rotate90; east => o _ rotate180; north => o _ rotate270; ENDCASE => ERROR; }; OrderRect: PROC [r: CD.Rect] RETURNS [CD.Rect] = { t: CD.Number; IF r.x1>r.x2 THEN {t_r.x1; r.x1_r.x2; r.x2_t}; IF r.y1>r.y2 THEN {t_r.y1; r.y1_r.y2; r.y2_t}; RETURN [r] }; CreateSymInst: PUBLIC PROC [name: Rope.ROPE, denotes: CD.Rect, dummySize: CD.Number, layer: CD.Layer, owner: ATOM, approachFrom: CDSymbolicObjects.Direction] RETURNS [symInst: CD.Instance] = { symOb: CD.Object; orient: CD.Orientation _ OrientFromDirection[approachFrom]; loc: CD.Position; denotes _ OrderRect[denotes]; IF denotes.x1#denotes.x2 AND denotes.y1#denotes.y2 THEN { <<--pin>> loc _ CDBasics.BaseOfRect[denotes]; symOb _ CreatePin[CDBasics.OrientedSize[CDBasics.SizeOfRect[denotes], orient]]; } ELSE IF denotes.x1=denotes.x2 AND denotes.y1=denotes.y2 THEN { <<--mark>> symOb _ CreateMark[dummySize]; loc _ [x: denotes.x1, y: denotes.y1]; } ELSE { <<--segment>> l: CD.Number; IF denotes.x1=denotes.x2 THEN { l _ denotes.y2-denotes.y1; IF approachFrom=south OR approachFrom=north THEN { <<-- erroneous parameters..>> approachFrom _ west; orient _ OrientFromDirection[approachFrom]; } } ELSE { l _ denotes.x2-denotes.x1; IF approachFrom=west OR approachFrom=east THEN { <<-- erroneous parameters..>> approachFrom _ south; orient _ OrientFromDirection[approachFrom]; } }; symOb _ CreateSegment[length: l, dummyWidth: dummySize]; loc _ CDBasics.BaseOfRect[denotes]; SELECT approachFrom FROM west => NULL; south => loc.x _ loc.x+symOb.bbox.y2; east => loc.y _ loc.y+symOb.bbox.y2; north => NULL; ENDCASE => ERROR; }; layer _ CDLayers.AbstractToPaint[layer]; symInst _ CDInstances.NewInst[ob: symOb, trans: [loc, orient]]; IF name#NIL THEN SetName[symInst, name]; IF layer#CD.undefLayer THEN SetLayer[symInst, layer]; IF owner#NIL THEN SetOwner[symInst, owner]; }; ObDenotes: PROC [ob: CD.Object] RETURNS [CD.Rect] = { RETURN [SELECT TRUE FROM ob.class=pinClass => ob.bbox, ob.class=segmentClass => [x1: 0, y1: 0, x2: 0, y2: ob.bbox.y2], ob.class=markClass => [0, 0, 0, 0], ENDCASE => CD.InterestRect[ob]] }; Denotes: PUBLIC PROC [symInst: CD.Instance] RETURNS [CD.Rect] = { RETURN [CDBasics.MapRect[ObDenotes[symInst.ob], symInst.trans]] }; <<>> EnumerateSymbolicObs: PUBLIC PROC [cellOb: CD.Object_NIL, eachInst: CDSymbolicObjects.InstEnumerator] RETURNS [quit: BOOL_FALSE] = { WITH cellOb.specific SELECT FROM c: CD.CellSpecific => { EachInst: CDCells.InstEnumerator = { IF IsSymbolicOb[inst.ob] THEN quit _ eachInst[inst]; -- do NOT catch errors }; quit _ CDCells.EnumerateInstances[cellOb, EachInst]; }; ip: CDImports.ImportSpecific => { -- HACK? until imports handle symbolic objects more reasonably IF ip.boundOb=NIL THEN RETURN [TRUE]; quit _ EnumerateSymbolicObs[ip.boundOb, eachInst]; RETURN }; ENDCASE => RETURN [TRUE]; }; FindSymbolicObs: PUBLIC PROC [cellOb: CD.Object_NIL, name: Rope.ROPE] RETURNS [il: CD.InstanceList_NIL] = { Enumerate: CDSymbolicObjects.InstEnumerator = { IF Rope.Equal[GetName[inst], name] THEN il _ CONS[inst, il]; }; [] _ EnumerateSymbolicObs[cellOb, Enumerate]; }; <<>> WritePinOrSegment: CD.InternalWriteProc = { CDIO.WritePos[h, CDBasics.SizeOfRect[ob.bbox]]; }; WriteMark: CD.InternalWriteProc = { }; ReadPin: CD.InternalReadProc = { RETURN [CreatePin[CDIO.ReadPos[h]]] }; ReadSegment: CD.InternalReadProc = { p: CD.Position _ CDIO.ReadPos[h]; RETURN [CreateSegment[p.y, p.x]] }; ReadMark: CD.InternalReadProc = { RETURN [markObject] }; Describe: CD.DescribeProc = { RETURN [Rope.Cat[CDOps.LayerRope[GetL[readOnlyInstProps]], " ", ob.class.description]]; }; ShowSelectedSymRL: CD.DrawProc = { pr.drawRect[pr, CDBasics.MapRect[ob.bbox, trans], CD.shadeLayer] }; DrawPin: CD.DrawProc = { DrawPinInContext: PROC [context: Imager.Context, ob: CD.Object, layer: CD.Layer] = { Imager.MaskVector[context, [0, 0], [ob.bbox.x2, ob.bbox.y2]]; Imager.MaskVector[context, [0, ob.bbox.y2], [ob.bbox.x2, 0]]; }; IF pr.symbolics AND (pr.scaleHint*MIN[ob.bbox.y2, ob.bbox.x2]>3 OR pr.scaleHint<=0) THEN { pr.drawContext[pr, DrawPinInContext, ob, trans, pinLayer]; pr.drawComment[pr: pr, r: CDBasics.MapRect[ob.bbox, trans], comment: GetN[readOnlyInstProps]] }; }; DrawSegment: CD.DrawProc = { DrawSegmentInContext: PROC [context: Imager.Context, ob: CD.Object, layer: CD.Layer] = { Imager.MaskVector[context, [0, 0], [0, ob.bbox.y2]]; Imager.MaskVector[context, [0, 0], [ob.bbox.x2, ob.bbox.y2/2]]; Imager.MaskVector[context, [0, ob.bbox.y2], [ob.bbox.x2, ob.bbox.y2/2]]; }; IF pr.symbolics AND (pr.scaleHint*ob.bbox.y2>3 OR pr.scaleHint<=0) THEN { pr.drawContext[pr, DrawSegmentInContext, ob, trans, segmentLayer]; pr.drawComment[pr: pr, r: CDBasics.MapRect[ob.bbox, trans], comment: GetN[readOnlyInstProps]] } }; DrawMark: CD.DrawProc = { DrawPath: PROC [context: Imager.Context, ob: CD.Object, layer: CD.Layer] = { Imager.MaskFillTrajectory[context, markObjectPath]; }; IF pr.symbolics AND (pr.scaleHint*ob.bbox.y2>2 OR pr.scaleHint<=0) THEN { pr.drawContext[pr, DrawPath, markObject, trans, markLayer] } }; ChangePinLayer: CD.ChangeLayerProc = { layer _ CDLayers.AbstractToPaint[layer]; SetLayer[inst, layer]; }; Init[]; END.