<> <> <> <> DIRECTORY CD, CDBasics, CDDrawQueue, CDPrivate, CDSequencer, CDViewer, CDViewerBase, CDVPrivate, CDVScale, Rope USING [ROPE, Equal], ViewerClasses; CDViewerImpl: CEDAR PROGRAM IMPORTS CDBasics, CDDrawQueue, CDPrivate, CDSequencer, CDViewerBase, CDVPrivate, CDVScale, Rope EXPORTS CDViewer SHARES CDVPrivate, CDPrivate = BEGIN ViewerList: TYPE = LIST OF ViewerClasses.Viewer; ViewersOf: PUBLIC PROC[design: REF] RETURNS [vl: ViewerList_NIL] = BEGIN WITH design SELECT FROM me: CDVPrivate.VRef => IF me.viewer#NIL THEN RETURN [LIST[me.viewer]]; comm: CDSequencer.Command => RETURN [ViewersOf[comm.ref]]; ENDCASE => NULL; FOR l: LIST OF CDVPrivate.VRef _ CDVPrivate.allVRefs, l.rest WHILE l#NIL DO IF (design=l.first.actualDesign OR design=l.first.actualDesign.technology OR design=NIL) AND l.first.viewer#NIL THEN vl _ CONS[l.first.viewer, vl]; ENDLOOP END; VisibleRect: PUBLIC PROC [viewer: ViewerClasses.Viewer] RETURNS [r: CD.Rect _ CDBasics.empty] = <<--undefined if viewer not open or not ChipNDale design>> BEGIN IF viewer#NIL THEN WITH viewer.data SELECT FROM me: CDVPrivate.VRef => r _ me.dClip; ENDCASE => NULL; END; DesignOf: PUBLIC PROC [viewer: ViewerClasses.Viewer] RETURNS [design: CD.Design _ NIL] = <<--NIL if not a ChipNDale design>> BEGIN IF viewer#NIL THEN WITH viewer.data SELECT FROM me: CDVPrivate.VRef => design _ me.actualDesign ENDCASE => NULL; END; ShowPosition: PUBLIC PROC[viewer: ViewerClasses.Viewer, pos: CD.Position] = <<--moves viewer such that pos is in visible area (does not open closed viewer)>> <<--approximative only>> BEGIN IF viewer#NIL AND viewer.data#NIL AND ISTYPE[viewer.data, CDVPrivate.VRef] THEN { viewerCenterOffset: CD.Position _ [viewer.cw/2, viewer.ch/2]; designCenterOffset: CD.Position; me: CDVPrivate.VRef = NARROW[viewer.data]; dscale: CDVScale.ScaleRec _ CDVScale.MakeScale[nscale: me.scale.nscale, grid: me.scale.grid]; IF CDBasics.InsidePos[pos, me.deviceDrawRef.interestClip] THEN RETURN; CDDrawQueue.Flush[me.ct]; --we change the scaleing info! somebody might be drawing designCenterOffset _ CDVScale.ViewerToDesignPosition[dscale, viewerCenterOffset]; dscale _ CDVScale.MakeScale[nscale: me.scale.nscale, grid: me.scale.grid, off: CDBasics.SubPoints[pos, designCenterOffset]]; me.intendedScale _ dscale; RepaintViewer[me]; }; END; ShowAndScale: PUBLIC PROC[viewer: ViewerClasses.Viewer, rect: CD.Rect] = <<--moves and scales viewer such that rect is in visible area (does not open closed viewer)>> <<--approximative only>> BEGIN IF viewer#NIL AND viewer.data#NIL AND ISTYPE[viewer.data, CDVPrivate.VRef] THEN { me: CDVPrivate.VRef = NARROW[viewer.data]; dscale: CDVScale.ScaleRec; off: CD.Position _ CDBasics.Center[rect]; s: CARDINAL _ 0; CDDrawQueue.Flush[me.ct]; --we change the scaleing info! somebody might be drawing FOR j: CARDINAL IN [0..CDVScale.scaleNum) DO s _ j; dscale _ CDVScale.MakeScale[nscale: s, grid: 1]; IF CDVScale.ViewerToDesignScalar[dscale, viewer.cw]>(rect.x2-rect.x1) AND CDVScale.ViewerToDesignScalar[dscale, viewer.ch]>(rect.y2-rect.y1) THEN EXIT; ENDLOOP; dscale _ CDVScale.MakeScale[nscale: s, grid: 1]; off.x _ off.x - CDVScale.ViewerToDesignScalar[dscale, viewer.cw]/2; off.y _ off.y - CDVScale.ViewerToDesignScalar[dscale, viewer.ch]/2; dscale _ CDVScale.MakeScale[nscale: s, grid: me.scale.grid, off: off]; me.intendedScale _ dscale; RepaintViewer[me]; }; END; CreateViewer: PUBLIC PROC [design: CD.Design, openDialogue: BOOL] RETURNS [ViewerClasses.Viewer] = BEGIN IF openDialogue THEN CDSequencer.OpenDialogue[design]; RETURN [CDVPrivate.CreateViewer[design]] END; FindDesign: PUBLIC PROC[name: Rope.ROPE, case: BOOL _ FALSE] RETURNS [CD.Design] = <<--only designs with viewers can be found;>> <<--if multiple designs have the same name, find arbitrary one>> BEGIN FOR l: LIST OF CDVPrivate.VRef _ CDVPrivate.allVRefs, l.rest WHILE l#NIL DO IF Rope.Equal[l.first.actualDesign.name, name, case] THEN RETURN[l.first.actualDesign]; ENDLOOP; RETURN [NIL] END; EnumDesigns: PROC[p: CDPrivate.DesignEnumerator] RETURNS [quit: BOOL_FALSE] = BEGIN FOR l: LIST OF CDVPrivate.VRef _ CDVPrivate.allVRefs, l.rest WHILE l#NIL AND ~quit DO quit _ p[l.first.actualDesign]; ENDLOOP; END; GetViewer: PUBLIC PROC [comm: CDSequencer.Command] RETURNS [v: ViewerClasses.Viewer _ NIL] = BEGIN IF comm#NIL THEN WITH comm.ref SELECT FROM my: CDVPrivate.VRef => RETURN [my.viewer] ENDCASE => NULL END; LastViewer: PUBLIC PROC[] RETURNS [ViewerClasses.Viewer]= BEGIN RETURN [CDVPrivate.LastViewer[]] END; <<--########################################>> <<--extensions>> RepaintViewer: PROC[vRef: CDVPrivate.VRef] = INLINE BEGIN CDDrawQueue.Flush[vRef.ct]; CDDrawQueue.QueueInsertDrawCommand[vRef.ct, CDDrawQueue.Request[$changeScale, CDBasics.universe]]; END; ToInt: PROC [ref: REF] RETURNS [i: INT_0] = INLINE { WITH ref SELECT FROM ri: REF INT => i _ ri^ ENDCASE => NULL }; GetGrid: ViewerClasses.GetProc = { me: CDVPrivate.VRef = NARROW[self.data]; RETURN [NEW[INT_me.scale.grid]] }; SetGrid: ViewerClasses.SetProc = { maxGrid: INT = 2600; --compute carefully such that no overflow can occur vRef: CDVPrivate.VRef = NARROW[self.data]; CDDrawQueue.Flush[vRef.ct]; vRef.intendedScale _ CDVScale.MakeScale[ off: vRef.scale.off, nscale: vRef.scale.nscale, grid: MIN[maxGrid, MAX[1, ToInt[data]]] ]; RepaintViewer[vRef]; }; <<--########################################>> CDViewerBase.ImplementGetProc[$Grid, GetGrid]; CDViewerBase.ImplementSetProc[$Grid, SetGrid]; CDPrivate.InstallDesignEnumerator[EnumDesigns]; END.