DIRECTORY CD USING [LayerKey, Object, Position, undefLayer], CDBasics USING [BaseOfRect, ComposeTransform, MapRect, NonEmpty, SizeOfRect], Checksum USING [ComputeChecksum], Core USING [CellType, Wire], CoreClasses USING [CellInstance, recordCellClass, RecordCellType, transistorCellClass], CoreGeometry USING [BBox, CellInstance, CellType, Decoration, EachInstanceProc, EnumerateGeometry, FlattenInstance, GetObject, GetTrans, Instance, Layer, Transformation, Wire], CoreOps USING [GetCellTypeName], CoreView USING [CoreCell, Layout, Rect, Viewer], CStitching USING [all, Area, ChangeEnumerateArea, ChangeRect, DumpCache, EnumerateArea, EnumerateNeighborhood, NewTesselation, RectProc, Region, ResetTesselation, Tesselation, Tile, TileProc], Icons USING [NewIconFromFile], Imager USING [black, ClipRectangle, Color, Context, ConstantColor, Font, MakeGray, MaskRectangle, MaskVector, MaskVectorI, Rectangle, ScaleT, SetColor, SetFont, SetPriorityImportant, SetStrokeEnd, SetStrokeJoint, SetStrokeWidth, SetXY, ShowRope, StrokeEnd, TranslateT, VEC, white], ImagerBackdoor USING [GetBounds], ImagerColor USING [ColorFromRGB, ConstantColor, RGB], ImagerColorPrivate USING [RGBFromColor], ImagerTransformation USING [Transformation], IO USING [card, int, PutR1], Menus USING [AppendMenuEntry, ClickProc, CreateEntry, CreateMenu, Menu, MenuEntry], MessageWindow USING [Append, Blink, Clear], NectarineColors USING [LayerColour, SetLayerColourTable], Process USING [CheckForAbort], Real USING [Fix, Float], RefTab USING [Create, EachPairAction, Fetch, Insert, Key, Pairs, Ref], Rope USING [Cat, ROPE], VFonts USING [defaultFont], ViewerClasses USING [DestroyProc, HScrollProc, PaintProc, ScrollProc, ViewerClass, ViewerClassRec, ViewerFlavor, ViewerRec], ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass], WindowManager USING [colorDisplayOn]; CoreViewImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, Checksum, CoreGeometry, CoreOps, CoreClasses, CStitching, Icons, Imager, ImagerBackdoor, ImagerColor, ImagerColorPrivate, IO, Menus, MessageWindow, NectarineColors, Process, Real, RefTab, Rope, VFonts, ViewerOps, WindowManager EXPORTS CoreView ~ BEGIN OPEN CoreView, Real; break: SIGNAL ~ CODE; -- for debugging Font: TYPE ~ Imager.Font; Color: TYPE ~ Imager.Color; Context: TYPE ~ Imager.Context; Rectangle: TYPE ~ Imager.Rectangle; Transformation: TYPE ~ ImagerTransformation.Transformation; ROPE: TYPE ~ Rope.ROPE; Region: TYPE ~ LIST OF REF CStitching.Region; Tess: TYPE ~ CStitching.Tesselation; Tile: TYPE ~ CStitching.Tile; TileAndContext: TYPE ~ REF TcRec; TcRec: TYPE ~ RECORD [tile: Tile, context: Context]; Transf: TYPE ~ CoreGeometry.Transformation; CoreInst: TYPE ~ CoreGeometry.CellInstance; FakeInst: TYPE ~ CoreGeometry.Instance; Wire: TYPE ~ CoreGeometry.Wire; Layer: TYPE ~ CoreGeometry.Layer; debugViewer: PUBLIC Viewer; monitorHandle: PUBLIC Tess; -- needed fom Cedar 7.0 on because a break-point in a paint procedure will lock the column identity: Transf; -- READONLY it is the default rectClass: ATOM ~ $Rect; markClass: ATOM ~ $AlignmentMarkOb; segmentClass: ATOM ~ $SymbolicSegment; pinClass: ATOM ~ $PinOb0; empty: REF ~ NIL; nothing: REF INT ~ NEW [INT]; outline: REAL ~ 0; minInteger: INT ~ INTEGER.FIRST; maxInteger: INT ~ INTEGER.LAST; State: TYPE = REF StateRec; StateRec: TYPE = RECORD [ previousColour: Color _ NIL, previousStrokeWidth: REAL _ -1024.0, tess: Tess, boundingBox, window: Rectangle, translation: Imager.VEC _ [0.0, 0.0], -- initialization imporant for caches scale: REAL, bottomSB, rightSB: INTEGER _ 100, -- caches: initialization imporant topSB, leftSB: INTEGER _ 0, -- caches: initialization imporant resetPainting: BOOL _ TRUE, -- initialization imporant for caches attributes: Layout, abort: REF BOOL]; GeometryView: PUBLIC PROC [cell: CoreCell, geom: Layout, abortFlag: REF BOOL] RETURNS [viewer: Viewer] ~ BEGIN state: State ~ NEW [StateRec]; BEGIN OPEN state; abort _ IF (abortFlag # NIL) THEN abortFlag ELSE NEW [BOOL _ FALSE]; boundingBox _ window _ ImagerRect [CoreGeometry.BBox [[CoreGeometry.GetObject [geom, cell], identity]]]; tess _ CStitching.NewTesselation [stopFlag: abort]; previousColour _ NIL; attributes _ geom END; IF (EnumerateCore [cell, identity, EveryCell, state]) THEN RETURN; [] _ NectarineColors.SetLayerColourTable []; BlendAllColours; viewer _ InitializeViewer [cell, normal, state] END; -- GeometryView StartIncrementalView: PUBLIC PROC [cell: CoreCell, geom: Layout, abortFlag: REF BOOL] RETURNS [viewer: Viewer] ~ BEGIN state: State ~ NEW [StateRec]; BEGIN OPEN state; abort _ IF (abortFlag # NIL) THEN abortFlag ELSE NEW [BOOL _ FALSE]; boundingBox _ window _ ImagerRect [CoreGeometry.BBox [[CoreGeometry.GetObject [geom, cell], identity]]]; tess _ CStitching.NewTesselation [stopFlag: abort]; previousColour _ NIL; attributes _ geom END; viewer _ InitializeViewer [cell, labelled, state]; END; -- StartIncrementalView AddRectangle: PUBLIC PROC [viewer: Viewer, rect: Rect, label: REF ANY] ~ BEGIN state: State; InsertRect: CStitching.RectProc ~ BEGIN plane.ChangeRect [rect: rect, new: label] END; -- InsertRect IF (viewer = NIL) THEN RETURN ELSE state _ NARROW [viewer.data, State]; IF state.abort^ THEN RETURN; state.tess.ChangeEnumerateArea [rect: rect, eachRect: InsertRect, skip: nothing]; ViewerOps.PaintViewer [viewer: viewer, hint: client] END; -- AddRectangle ComposedTransf: PROC [parent: Transf, child: CoreInst, state: State] RETURNS [Transf] ~ BEGIN RETURN [CDBasics.ComposeTransform [CoreGeometry.GetTrans [state.attributes, child], parent]] END; -- ComposedTransf EachCell: TYPE ~ PROC [cell: CoreCell, transf: Transf, state: State]; EnumerateCore: PROC [cell: CoreCell, transf: Transf, action: EachCell, state: State] RETURNS [quit: BOOL _ FALSE] ~ BEGIN IF state.abort^ THEN RETURN [TRUE]; SELECT cell.class FROM CoreClasses.recordCellClass => BEGIN cellData: CoreClasses.RecordCellType ~ NARROW [cell.data]; FOR sub: NAT IN [0 .. cellData.size) DO subTransf: Transf ~ ComposedTransf [transf, cellData.instances[sub], state]; IF (EnumerateCore [cellData.instances[sub].type, subTransf, action, state]) THEN RETURN [TRUE] ENDLOOP END; ENDCASE => NULL; action [cell, transf, state]; quit _ state.abort^ END; -- EnumerateCore EveryCell: EachCell ~ BEGIN SELECT cell.class FROM CoreClasses.recordCellClass => BEGIN cellData: CoreClasses.RecordCellType ~ NARROW [cell.data]; FOR i: NAT IN [0 .. cellData.internal.size) DO IF state.abort^ THEN RETURN; EveryWire [state: state, cell: cell, w: cellData.internal[i], transf: transf] ENDLOOP END; CoreClasses.transistorCellClass => FOR i: NAT IN [0 .. cell.public.size) DO IF state.abort^ THEN RETURN; EveryWire [state: state, cell: cell, w: cell.public[i], transf: transf] ENDLOOP ENDCASE => NULL -- Print warning END; -- EveryCell EveryWire: PROC [cell: CoreCell, w: Wire, transf: Transf, state: State] ~ BEGIN EveryRect: CoreGeometry.EachInstanceProc ~ BEGIN rect: Rect ~ CDBasics.MapRect [CoreGeometry.BBox [instance], transf]; dec: Tess ~ state.tess; l: Layer ~ instance.obj.layer; InsertRect: CStitching.RectProc ~ BEGIN WITH oldValue SELECT FROM b: Blend => IF NOT b.flavours[l] THEN dec.ChangeRect [rect: rect, new: ColourTile [b, l]]; ENDCASE => BEGIN b: Blend _ NEW [BlendRec]; dec.ChangeRect [rect: rect, new: ColourTile [b, l]] END END; -- InsertRect IF state.abort^ THEN RETURN [state.abort^]; SELECT instance.obj.class.objectType FROM rectClass => IF (CDBasics.NonEmpty [rect]) THEN dec.ChangeEnumerateArea [rect: rect, eachRect: InsertRect, skip: nothing]; markClass, segmentClass, pinClass => NULL; ENDCASE => quit _ CoreGeometry.FlattenInstance [instance, EveryRect]; END; -- EveryRect [] _ state.attributes.EnumerateGeometry [w, EveryRect]; FOR i: INT IN [0 .. w.size) DO [] _ state.attributes.EnumerateGeometry [w.elements[i], EveryRect] ENDLOOP END; -- EveryWire ViewerFlavor: TYPE ~ ViewerClasses.ViewerFlavor; normal: ViewerFlavor ~ $CoreView; labelled: ViewerFlavor ~ $LabelledCoreView; InitializeViewerClasses: PROC ~ BEGIN classN: ViewerClasses.ViewerClass _ NEW [ViewerClasses.ViewerClassRec]; classL: ViewerClasses.ViewerClass _ NEW [ViewerClasses.ViewerClassRec]; classMenu: Menus.Menu ~ Menus.CreateMenu []; abortButton: Menus.MenuEntry ~ Menus.CreateEntry [name: "Abort", proc: Abort, guarded: TRUE]; zoomInButton: Menus.MenuEntry ~ Menus.CreateEntry [name: "Zoom-In", proc: ZoomIn]; zoomOutButton: Menus.MenuEntry ~ Menus.CreateEntry [name: "Zoom-Out", proc: ZoomOut]; everythingButton: Menus.MenuEntry ~ Menus.CreateEntry [name: "Reset", proc: Everything]; Menus.AppendMenuEntry [classMenu, abortButton]; Menus.AppendMenuEntry [classMenu, zoomInButton]; Menus.AppendMenuEntry [classMenu, zoomOutButton]; Menus.AppendMenuEntry [classMenu, everythingButton]; BEGIN OPEN classN; flavor _ normal; paint _ Paint; destroy _ Destroy; scroll _ VerticalTranslation; hscroll _ HorizontalTranslation; menu _ classMenu; icon _ Icons.NewIconFromFile ["[DATools]CoreView>CoreView.Icons", 0]; cursor _ crossHairsCircle END; classL^ _ classN^; classL.flavor _ labelled; classL.icon _ Icons.NewIconFromFile ["[DATools]CoreView>CoreView.Icons", 1]; ViewerOps.RegisterViewerClass [normal, classN]; ViewerOps.RegisterViewerClass [labelled, classL] END; -- InitializeViewerClasses InitializeViewer: PROC [cell: CoreCell, flavor: ViewerFlavor, state: State] RETURNS [viewer: Viewer] ~ BEGIN info: ViewerClasses.ViewerRec; BEGIN OPEN info; label _ CoreOps.GetCellTypeName [cell]; name _ IF (flavor = normal) THEN label ELSE label.Cat [" debugging"]; column _ IF WindowManager.colorDisplayOn THEN color ELSE left; scrollable _ TRUE; hscrollable _ TRUE; iconic _ (flavor = labelled); guardDestroy _ TRUE; data _ state END; viewer _ ViewerOps.CreateViewer [flavor, info] END; -- InitializeViewer Paint: ViewerClasses.PaintProc ~ BEGIN state: State ~ NARROW [self.data]; ChangeStrokeWidth: PROC [state: State, w: REAL] ~ INLINE BEGIN IF (w < 0) OR (w # state.previousStrokeWidth) THEN BEGIN context.SetStrokeWidth [w]; state.previousStrokeWidth _ w END END; -- ChangeStrokeWidth ChangeColour: PROC [colour: Color] ~ INLINE BEGIN a: ImagerColor.RGB ~ RGBFromColour [colour]; b: ImagerColor.RGB ~ RGBFromColour [state.previousColour]; IF (a.R # b.R) OR (a.G # b.G) OR (a.B # b.B) OR (state.previousColour = NIL) THEN BEGIN IF (a.R = 0.0) AND (a.G = 0.0) AND (a.B = 0.0) THEN context.SetColor [blackBlack] ELSE context.SetColor [colour]; state.previousColour _ colour END END; -- ChangeColour FastMaskVector: PROC [context: Context, x1, y1, x2, y2: INT] ~ BEGIN IF ((x1 >= minInteger) AND (y1 >= minInteger) AND (x2 <= maxInteger) AND (y2 <= maxInteger)) THEN context.MaskVectorI [x1, y1, x2, y2] ELSE context.MaskVector [[Float[x1], Float[y1]], [Float[x2], Float[y2]]] END; -- FastMaskVector SouthRim: CStitching.TileProc ~ BEGIN tc: TileAndContext ~ NARROW [data]; IF (tile.value # tc.tile.value) THEN BEGIN tr: Rect ~ tc.tile.Area; nr: Rect ~ tile.Area; x1: INT ~ MAX [tr.x1, nr.x1]; x2: INT ~ MIN [tr.x2, nr.x2]; IF (x1 < x2) THEN FastMaskVector [tc.context, x1, tr.y1, x2, tr.y1] END END; -- SouthRim EastRim: CStitching.TileProc ~ BEGIN tc: TileAndContext ~ NARROW [data]; IF (tile.value # tc.tile.value) THEN BEGIN tr: Rect ~ tc.tile.Area; nr: Rect ~ tile.Area; y1: INT ~ MAX [tr.y1, nr.y1]; y2: INT ~ MIN [tr.y2, nr.y2]; IF (y1 < y2) THEN FastMaskVector [tc.context, tr.x2, y1, tr.x2, y2] END END; -- EastRim NorthRim: CStitching.TileProc ~ BEGIN tc: TileAndContext ~ NARROW [data]; IF (tile.value # tc.tile.value) THEN BEGIN tr: Rect ~ tc.tile.Area; nr: Rect ~ tile.Area; x1: INT ~ MAX [tr.x1, nr.x1]; x2: INT ~ MIN [tr.x2, nr.x2]; IF (x1 < x2) THEN FastMaskVector [tc.context, x1, tr.y2, x2, tr.y2] END END; -- NorthRim WestRim: CStitching.TileProc ~ BEGIN tc: TileAndContext ~ NARROW [data]; IF (tile.value # tc.tile.value) THEN BEGIN tr: Rect ~ tc.tile.Area; nr: Rect ~ tile.Area; y1: INT ~ MAX [tr.y1, nr.y1]; y2: INT ~ MIN [tr.y2, nr.y2]; IF (y1 < y2) THEN FastMaskVector [tc.context, tr.x1, y1, tr.x1, y2] END END; -- WestRim NewPrintTile: CStitching.TileProc ~ BEGIN state: State ~ NARROW [data]; b: Blend ~ NARROW [tile.value]; r: Rect ~ CStitching.Area [tile]; -- not the area but the rectangle ! ir: Rectangle ~ ImagerRect [r]; median: INT; ChangeColour [b.blend]; context.SetStrokeEnd [butt]; IF (ir.w > ir.h) THEN BEGIN ChangeStrokeWidth [state, ir.h]; median _ (r.y1 + r.y2) / 2; FastMaskVector [context, r.x1, median, r.x2, median] END ELSE BEGIN ChangeStrokeWidth [state, ir.w]; median _ (r.x1 + r.x2) / 2; FastMaskVector [context, median, r.y1, median, r.y2] END; IF state.abort^ THEN ERROR ABORTED; Process.CheckForAbort; IF (outline >= 0.0) AND (b.blend # blackBlack) THEN BEGIN tc: TileAndContext ~ NEW [TcRec _ [tile, context]]; ChangeColour [blackBlack]; ChangeStrokeWidth [state, outline]; context.SetStrokeEnd [square]; state.tess.EnumerateNeighborhood [tile, SouthRim, WestRim, NorthRim, EastRim, tc, nothing] END END; -- NewPrintTile PrintTile: CStitching.TileProc ~ BEGIN b: Blend ~ NARROW [tile.value]; r: Rect ~ CStitching.Area [tile]; -- not the area but the rectangle ! IF state.abort^ THEN RETURN; ChangeColour [b.blend]; context.MaskRectangle [ImagerRect [r]] END; -- PrintTile PrintLabeledTile: CStitching.TileProc ~ BEGIN r: Rect ~ CStitching.Area [tile]; -- not the area but the rectangle ! l: CARD; IF state.abort^ THEN RETURN; ChangeColour [lightGrey]; context.MaskRectangle [ImagerRect [r]]; ChangeColour [blackBlack]; context.SetStrokeWidth [0.0]; context.MaskVectorI [r.x1, r.y1, r.x2, r.y1]; -- South context.MaskVectorI [r.x2, r.y1, r.x2, r.y2]; -- East context.MaskVectorI [r.x2, r.y2, r.x1, r.y2]; -- North context.MaskVectorI [r.x1, r.y2, r.x1, r.y1]; -- West TRUSTED {l _ LOOPHOLE [tile.value, CARD]}; context.SetXY [[r.x1, r.y1]]; context.ShowRope [IO.PutR1 [IO.card [l]]] END; -- PrintLabeledTile state.abort^ _ FALSE; monitorHandle _ state.tess; state.previousColour _ NIL; context.SetStrokeEnd [butt]; state.window _ ImagerBackdoor.GetBounds [context]; -- needed for scroll bars IF (self.class.flavor = normal) AND ((self.column = color) OR (NOT clear)) THEN BEGIN context.SetColor [whiteWhite]; context.MaskRectangle [state.window] END; IF state.abort^ THEN {state.abort^ _ FALSE; RETURN [TRUE]}; context.SetPriorityImportant [FALSE]; IF state.resetPainting THEN BEGIN -- important for initialization of caches state.translation _ [state.boundingBox.x, state.boundingBox.y]; state.scale _ MIN [(state.window.w / state.boundingBox.w), (state.window.h / state.boundingBox.h)]; state.resetPainting _ FALSE END; context.TranslateT [state.translation]; context.ScaleT [state.scale]; state.window _ ImagerBackdoor.GetBounds [context]; -- needed for scroll bars context.ClipRectangle [state.window]; context.SetStrokeJoint [miter]; context.SetStrokeWidth [0]; context.SetStrokeEnd [square]; context.SetFont [VFonts.defaultFont]; SELECT self.class.flavor FROM normal => state.tess.EnumerateArea [rect: CStitching.all, eachTile: NewPrintTile, data: state, skip: empty]; labelled => state.tess.EnumerateArea [rect: CStitching.all, eachTile: PrintLabeledTile, data: state, skip: empty]; ENDCASE => ERROR END; -- Paint VerticalTranslation: ViewerClasses.ScrollProc ~ BEGIN state: State ~ NARROW [self.data]; BEGIN OPEN state; SELECT op FROM query => BEGIN top _ MAX [topSB, 0]; bottom _ MIN [bottomSB, 100]; RETURN END; up => IF (window.y < boundingBox.y+boundingBox.h) THEN BEGIN translation.y _ translation.y + (Float [amount] / Float [self.ch]) * window.h; topSB _ Fix [(window.y + window.h) / (boundingBox.y + boundingBox.h) * 100.0]; bottomSB _ topSB + Fix [(window.h / boundingBox.h) * 100.0] END; down => IF (window.y+window.h > boundingBox.y) THEN BEGIN translation.y _ translation.y - (Float [amount] / Float [self.ch]) * window.h; topSB _ Fix [(window.y + window.h) / (boundingBox.y + boundingBox.h) * 100.0]; bottomSB _ topSB + Fix [(window.h / boundingBox.h) * 100.0] END; thumb => SELECT TRUE FROM shift AND control => ImportantMessage ["Invalid command"]; shift => BEGIN -- scale up (window becomes relatively smaller) factor: REAL ~ 10.0 / Float [amount + 10]; scale _ scale * factor; topSB _ Fix [((window.y + window.h) * factor) / (boundingBox.y + boundingBox.h) * 100.0]; bottomSB _ topSB + Fix [(window.h / boundingBox.h) * 100.0] END; control => BEGIN -- reset painting resetPainting _ TRUE; bottomSB _ rightSB _ 100; topSB _ leftSB _ 0 END; ENDCASE => BEGIN -- thumb sign: INTEGER _ IF (boundingBox.h > window.h) THEN -1 ELSE 1; translation.y _ sign * (boundingBox.y + (boundingBox.h * Float [amount] / 100.0)); topSB _ amount; bottomSB _ amount + Fix [(window.h / boundingBox.h) * 100.0] END; ENDCASE => ERROR; Trace [amount]; ViewerOps.PaintViewer [viewer: self, hint: client]; -- op <> query top _ MAX [topSB, 0]; bottom _ MIN [bottomSB, 100] END -- OPEN state END; -- VerticalTranslation HorizontalTranslation: ViewerClasses.HScrollProc ~ BEGIN state: State ~ NARROW [self.data]; BEGIN OPEN state; SELECT op FROM query => BEGIN right _ MIN [rightSB, 100]; left _ MAX [leftSB, 0]; RETURN END; right => IF (window.x < boundingBox.x+boundingBox.w) THEN BEGIN translation.x _ translation.x + (Float [amount] / Float [self.cw]) * window.w; leftSB _ Fix [(window.x + window.w) / (boundingBox.x + boundingBox.w) * 100.0]; rightSB _ leftSB + Fix [(window.w / boundingBox.w) * 100.0] END; left => IF (window.x+window.w > boundingBox.x) THEN BEGIN translation.x _ translation.x - (Float [amount] / Float [self.cw]) * window.w; leftSB _ Fix [(window.x + window.w) / (boundingBox.x + boundingBox.w) * 100.0]; rightSB _ leftSB + Fix [(window.w / boundingBox.w) * 100.0] END; thumb => SELECT TRUE FROM shift AND control => ImportantMessage ["Invalid command"]; shift => BEGIN -- scale down (window becomes relatively larger) factor: REAL ~ Float [amount + 10] / 10.0; scale _ scale * factor; leftSB _ Fix [((window.x + window.w) * factor) / (boundingBox.x + boundingBox.w) * 100.0]; rightSB _ leftSB + Fix [(window.w / boundingBox.w) * 100.0] END; control => BEGIN -- reset painting resetPainting _ TRUE; bottomSB _ rightSB _ 100; topSB _ leftSB _ 0 END; ENDCASE => BEGIN -- thumb sign: INTEGER _ IF (boundingBox.w > window.w) THEN -1 ELSE 1; translation.x _ sign * (boundingBox.x + (boundingBox.w * Float [amount] / 100.0)); leftSB _ amount; rightSB _ amount + Fix [(window.w / boundingBox.w) * 100.0] END; ENDCASE => ERROR; Trace [amount]; ViewerOps.PaintViewer [viewer: self, hint: client]; -- op <> query right _ MIN [rightSB, 100]; left _ MAX [leftSB, 0] END -- OPEN state END; -- HorizontalTranslation Destroy: ViewerClasses.DestroyProc ~ BEGIN state: State ~ NARROW [self.data]; state.tess.ResetTesselation []; CStitching.DumpCache END; -- Destroy Abort: Menus.ClickProc ~ BEGIN IF NOT ISTYPE [parent, Viewer] THEN ImportantMessage ["Implementation error"] ELSE BEGIN state: State ~ NARROW [NARROW [parent, Viewer].data]; state.abort^ _ TRUE END END; -- Abort ZoomIn: Menus.ClickProc ~ BEGIN IF NOT ISTYPE [parent, Viewer] THEN ImportantMessage ["Implementation error"] ELSE BEGIN v: Viewer ~ NARROW [parent]; state: State ~ NARROW [v.data]; BEGIN OPEN state; scale _ scale * 1.5; ViewerOps.PaintViewer [viewer: v, hint: client]; topSB _ Fix [(window.y + window.h) / (boundingBox.y + boundingBox.h) * 100.0]; bottomSB _ topSB + Fix [(window.h / boundingBox.h) * 100.0]; leftSB _ Fix [(window.x + window.w) / (boundingBox.x + boundingBox.w) * 100.0]; rightSB _ leftSB + Fix [(window.w / boundingBox.w) * 100.0] END END END; -- ZoomIn ZoomOut: Menus.ClickProc ~ BEGIN IF NOT ISTYPE [parent, Viewer] THEN ImportantMessage ["Implementation error"] ELSE BEGIN v: Viewer ~ NARROW [parent]; state: State ~ NARROW [v.data]; BEGIN OPEN state; scale _ scale / 1.5; ViewerOps.PaintViewer [viewer: v, hint: client]; topSB _ Fix [(window.y + window.h) / (boundingBox.y + boundingBox.h) * 100.0]; bottomSB _ topSB + Fix [(window.h / boundingBox.h) * 100.0]; leftSB _ Fix [(window.x + window.w) / (boundingBox.x + boundingBox.w) * 100.0]; rightSB _ leftSB + Fix [(window.w / boundingBox.w) * 100.0] END END END; -- ZoomOut Everything: Menus.ClickProc ~ BEGIN IF NOT ISTYPE [parent, Viewer] THEN ImportantMessage ["Implementation error"] ELSE BEGIN v: Viewer ~ NARROW [parent]; state: State ~ NARROW [v.data]; state.resetPainting _ TRUE; [] _ NectarineColors.SetLayerColourTable []; BlendAllColours; state.bottomSB _ state.rightSB _ 100; state.topSB _ state.leftSB _ 0; ViewerOps.PaintViewer [viewer: v, hint: client] END END; -- Everything Bitset: TYPE ~ PACKED ARRAY Layer OF BOOLEAN _ ALL [FALSE]; BlendKey: TYPE ~ REF Bitset; Blend: TYPE ~ REF BlendRec; BlendRec: TYPE ~ RECORD [count: Layer _ 0, flavours: Bitset, blend: Color _ NIL, area: CARD _ 0]; colourTable: RefTab.Ref ~ RefTab.Create [557, Match, Hash]; -- or 997 ColourTile: PROC [old: Blend, l: Layer] RETURNS [new: Blend] ~ BEGIN key: BlendKey ~ NEW [Bitset _ old.flavours]; key[l] _ TRUE; new _ NARROW [colourTable.Fetch[key].val, Blend]; IF (new = NIL) THEN BEGIN copy: Blend _ NEW [BlendRec _ [flavours: old.flavours]]; copy.count _ SUCC [old.count]; copy.flavours[l] _ TRUE; new _ copy; IF NOT colourTable.Insert [key, copy] THEN ERROR END END; -- ColourTile blackBlack: Color ~ Imager.black; whiteWhite: Color ~ Imager.white; grey: Color ~ Imager.MakeGray [0.36]; lightGrey: Color ~ Imager.MakeGray [0.18]; black: Color ~ ImagerColor.ColorFromRGB [[0.0, 0.0, 0.0]]; blue: Color ~ ImagerColor.ColorFromRGB [[0.0, 0.0, 1.0]]; unColour: ImagerColor.RGB ~ [0.0, 0.0, 0.0]; doubleYellowRGB: ImagerColor.RGB ~ [2.0, 2.0, 0.0]; doubleYellow: Color ~ ImagerColor.ColorFromRGB [doubleYellowRGB]; magentaRGB: ImagerColor.RGB ~ [1.0, 0.0, 1.0]; cyan: Color ~ ImagerColor.ColorFromRGB [[0.0, 1.0, 1.0]]; lightYellow: Color ~ ImagerColor.ColorFromRGB [[6.0/7.0, 6.0/7.0, 3.0/7.0]]; lightMagenta: Color ~ ImagerColor.ColorFromRGB [[5.0/7.0, 0.0, 5.0/7.0]]; BlendColours: RefTab.EachPairAction ~ BEGIN components: Blend ~ NARROW [val]; n: REAL _ Float [components.count]; comp: PACKED ARRAY Layer OF BOOLEAN _ components.flavours; mix: ImagerColor.RGB _ unColour; IF (components.blend # NIL) THEN RETURN [FALSE]; -- caching across sessions SELECT n FROM 0 => ERROR; -- should never have been allocated 1 => BEGIN i: Layer _ 0; WHILE NOT comp[i] DO i _ SUCC [i] ENDLOOP; components.blend _ NectarineColors.LayerColour [i] END; ENDCASE => BEGIN poly, diff, met, met2, cut, cut2, well: Layer _ 0; FOR i: Layer IN Layer DO IF comp[i] THEN SELECT CD.LayerKey[i] FROM $pol => poly _ i; $ndif, $pdif => diff _ i; $met => met _ i; $met2 => met2 _ i; $nwel => well _ i; $cut => cut _ i; $cut2 => {cut _ i; cut2 _ i}; ENDCASE => NULL ENDLOOP; IF (cut # 0) THEN components.blend _ IF (cut2 # 0) THEN blue ELSE black ELSE BEGIN -- Assume: all other colours have the same weight. IF (poly # 0) AND (diff # 0) THEN BEGIN -- Handle gates. mix _ doubleYellowRGB; comp[poly] _ comp[diff] _ FALSE END; IF (poly # 0) AND (met # 0) AND (diff = 0) THEN BEGIN -- Handle metal over poly. mix _ magentaRGB; n _ n - 1.0; comp[poly] _ comp[met] _ FALSE END; FOR i: Layer IN Layer DO -- Compute mean colour. IF comp[i] THEN BEGIN v: ImagerColor.RGB ~ RGBFromColour [NectarineColors.LayerColour[i]]; mix.R _ mix.R + v.R; mix.G _ mix.G + v.G; mix.B _ mix.B + v.B END ENDLOOP; IF (met2 # 0) THEN BEGIN -- make metal-2 transparent mix.R _ mix.R - 4.0/7.0; mix.B _ mix.B - 4.0/7.0; n _ n - 4.0/7.0 END; IF (well # 0) THEN BEGIN -- make wells transparent mix.R _ mix.R - 5.0/7.0; mix.G _ mix.G - 5.0/7.0; n _ n - 5.0/7.0; mix.B _ mix.B - (3.0/7.0 * 2.0/7.0) -- take out well lightener END; mix.R _ mix.R / n; mix.G _ mix.G / n; mix.B _ mix.B / n; components.blend _ ImagerColor.ColorFromRGB [mix] END END; RETURN [FALSE] END; -- BlendColours BlendAllColours: PROC ~ BEGIN [] _ colourTable.Pairs [BlendColours] END; -- BlendAllColours Hash: PROC [k: RefTab.Key] RETURNS [CARDINAL] ~ BEGIN TRUSTED BEGIN RETURN [Checksum.ComputeChecksum [0, SIZE [BlendKey], LOOPHOLE [k]]] END END; -- Hash Match: PROC [key1, key2: RefTab.Key] RETURNS [BOOL] ~ BEGIN k1: BlendKey ~ NARROW [key1, BlendKey]; k2: BlendKey ~ NARROW [key2, BlendKey]; RETURN [(k1^ = k2^)] END; -- Match ImagerRect: PROC [r: Rect] RETURNS [Rectangle] ~ BEGIN base: CD.Position ~ CDBasics.BaseOfRect [r]; size: CD.Position ~ CDBasics.SizeOfRect [r]; RETURN [[Float[base.x], Float[base.y], Float[size.x], Float[size.y]]] END; -- ImagerRect ImagerVec: PROC [p: CD.Position] RETURNS [Imager.VEC] ~ BEGIN RETURN [[Float[p.x], Float[p.y]]] END; -- ImagerVec RGBFromColour: PROC [c: Color] RETURNS [rgb: ImagerColor.RGB] ~ INLINE BEGIN WITH c SELECT FROM constant: Imager.ConstantColor => rgb _ ImagerColorPrivate.RGBFromColor [constant]; ENDCASE => rgb _ unColour; RETURN [rgb] END; -- RGBFromColour ImportantMessage: PROC [msg: ROPE] ~ BEGIN MessageWindow.Clear []; MessageWindow.Append [msg]; MessageWindow.Blink [] END; -- ImportantMessage Trace: PROC [i: INTEGER] ~ BEGIN MessageWindow.Clear []; MessageWindow.Append [IO.PutR1 [IO.int [i]]] END; -- Trace InitializeViewerClasses END. ψCoreViewImpl.mesa Copyright Σ 1987, 1988 by Xerox Corporation. All rights reserved. Written by Giordano Bruno Beretta, January 22, 1987 10:44:14 am PST gbb January 16, 1988 4:12:20 pm PST Bertrand Serlet April 2, 1987 3:56:13 pm PST Visualizes the Manhattan geometry in a Core data structure. Interfaces Draws the geometry in a Core data structure in a viewer using the Imager. Initializes a viewer into which rectangles can be drawn one at a time in the context of a given cell. Adds a rectangle to a viewer started with StartIncrementalView. The label field is loopholed to label the rectangle. [plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF] Core Returns the child's absolute coordinates. Enumerates the cell and does action on each subcell. [cell: CoreCell, transf: Transf, state: State] [instance: CdInsts] RETURNS [quit: BOOL _ FALSE] [plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF] Note that merging works correctly because of the use of the colour table. IF (instance.obj.class.objectType # rectClass) THEN break; Viewers & Context Set-up Initializes and registers the viewer classes. Draws the geometry in a Core data structure in a viewer using the Imager. [self: Viewer, context: Context, whatChanged: REF, clear: BOOL] RETURNS [quit: BOOL _ FALSE] Called by the window manager when the client should repaint the data on the screen. The context is clipped to the client screen area. whatChanged is just passed from the call to ViewerOps.PaintViewer, but will be NIL when the window manager requires a full repaint after moving a viewer on the screen. clear is a hint that the client background is white, so that the client can paint on the black bits if it so chooses. See comments for paintRectangles bit in the viewer class. Return quit~TRUE to stop without painting children. w < 0 means that it has not yet been set in this body. Must be fast as a bullet. At this point we know that only one colour representation is used. Must be fast as a bullet. Draw black using the grey colour model, so that it is placed in the black colour separation. Probably for speed reasons the Imager uses 16 bit integers. PROC [tile: REF Tile, data: REF] PROC [tile: REF Tile, data: REF] PROC [tile: REF Tile, data: REF] PROC [tile: REF Tile, data: REF] PROC [tile: REF Tile, data: REF] This is an experiment for Cedar 7.0. Michael Plass has changed the implementation of MaskVector so that it gives the result of PrintAlignedTile at the cost of PrintTile. PROC [tile: REF Tile, data: REF] PROC [tile: REF Tile, data: REF] context.SetColor [IF (self.column = color) THEN grey ELSE whiteWhite]; [self: Viewer, op: ScrollOp, amount: INTEGER, shift, control: BOOL _ FALSE] RETURNS [top, bottom: INTEGER _ LAST[INTEGER]] ScrollOp = {query, up, down, thumb} Client scrolling and scrolling feedback. If op is 'query' the client should return the percentage of the scrollable document at the top and bottom of the screen, or default if unknown. If op is 'up' or 'down' then amount is number of pixels to glitch. If op is 'thumb' then amount is percentage into document to scroll. The shift and control information reflects the state of the shift and control keys during the up, down, and thumb ops and may be interpreted by the client as desired. viewport: [self.cx, cy, cw, ch] A query is performed each time the mouse is on a scroll bar, hence this must be faster than a bullet. Note that the cached values may exceed the diplayed values to avoid referring to the window when it is moved back into the viewer. Note also that topSB and bottomSB cannot be computed trivially from amount, because amount is in pixels, while I have to return a percentage. The scroll bar is viewed as a scale from 1 to 10. Note that the cached values may exceed the diplayed values to avoid referring to the window when it is moved back into the viewer. [self: Viewer, op: HScrollOp, amount: INTEGER, shift, control: BOOL _ FALSE] RETURNS [left, right: INTEGER _ LAST[INTEGER]] HScrollOp = {query, left, right, thumb} Client scrolling and scrolling feedback. If op is 'query' the client should return the percentage of the scrollable document at the top and bottom of the screen, or default if unknown. If op is 'up' or 'down' then amount is number of pixels to glitch. If op is 'thumb' then amount is percentage into document to scroll. The shift and control information reflects the state of the shift and control keys during the up, down, and thumb ops and may be interpreted by the client as desired. A query is performed each time the mouse is on a scroll bar, hence this must be faster than a bullet. Note that the cached values may exceed the diplayed values to avoid referring to the window when it is moved back into the viewer. Called when the viewer has been destroyed for some reason. [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE] Color Blending Data is global Sets up a blending record for a tile. Must be fast as a bullet. Takes the layers covering a tile and blend an RBG-colour out of them. [key: Key, value: Value] RETURNS [quit: BOOLEAN _ FALSE] Find exception layers. Cuts always win. Reinitialize mix by yellow and eliminate poly and diff. Since gates are very important, they are given double weight. The logarithm of the number of colours is two, that of the rectangles is six. PROC [Key] RETURNS [CARDINAL] RefTab.EqualProc Conversions CdPos: PROC [v: Imager.VEC] RETURNS [CD.Position] ~ BEGIN RETURN [[Round[v.x], Round[v.y]]] END; -- CdPos Assume that LayerColour had previously been called. Writes a message in the ChipNDale terminal viewer and in the Message Window at the top of the LF screen and makes it blink. Initializations gbb June 11, 1987 11:53:55 am PDT Added a monitor handle because from Cedar 7.0 on, when a break-point is put in a paint procedure, the whole column with the viewer remains locked. changes to: OPEN, Paint gbb June 11, 1987 12:07:16 pm PDT Added outline feature from Nectarine. changes to: DIRECTORY, OPEN, ChangeStrokeWidth (local of Paint), ChangeColour (local of Paint), FastMaskVector (local of Paint), SouthRim (local of Paint), EastRim (local of Paint), NorthRim (local of Paint), WestRim (local of Paint), NewPrintTile (local of Paint), PrintTile (local of Paint), Paint, END gbb June 11, 1987 5:35:49 pm PDT Solved a race condition with the Imager. Got rid by brute force from the special colours, since the mechanism does not work. Probably not all colours are registered, or the Imager cannot find them any more or whatever: out they are. changes to: DIRECTORY, IMPORTS, GeometryView, InitializeViewer, SetLayerColourTable gbb June 25, 1987 2:13:59 pm PDT Gets layers colors from Nectarine instead of ChipNDale. changes to: DIRECTORY, IMPORTS, GeometryView, Everything, BlendColours Κ’˜codešœ™KšœB™BKšœC™CK™#K™,—K™K™;code2šΟk ˜ Kšœœ*˜2Kšœ œ?˜MKšœ œ˜!Kšœœ˜Kšœ œF˜WKšœ œž˜°Kšœœ˜ Kšœ œ"˜0Kšœ œ°˜ΐKšœœ˜Kšœœœœ˜™Kšœœ ˜!Kšœ œœ˜5Kšœœ˜(Kšœœ˜,Kšœœ˜KšœœH˜SKšœœ˜+Kšœœ$˜9Kšœœ˜Kšœœ˜Kšœœ:˜FKšœœœ˜Kšœœ˜Kšœœi˜|Kšœ œ2˜AKšœœ˜%—LšΠln œœ˜Lšœœ…œf˜ψLšœ ˜šœ˜IunitšœœœΟc˜'Mšœœ˜Kšœœ˜Kšœ œ˜Kšœ œ˜#Kšœœ'˜;Kšœœœ˜Kš œœœœœ˜-Kšœœ˜$Kšœœ˜Kšœœœ˜!Kšœœœ ˜4Kšœœ˜+Kšœ œ˜+Kšœ œ˜'Kšœœ˜Kšœœ˜!Lšœ œ˜LšœœŸZ˜vLšœŸœŸ˜/Kšœ œ ˜Kšœ œ˜#Kšœœ˜&Kšœ œ ˜Kšœœœ˜Kš œ œœœœ˜Kšœ œ˜Kšœ œœœ˜ Kšœ œœœ˜Mšœœœ ˜Kš!œ œœœœLœŸ%œœœŸ"œœŸ"œœœŸ%œœœ˜Ν—head™ š Οn œœœ+œœœ˜nKšœI™IKšœœ ˜šœœ˜Kšœœœœ œœœœ˜DLšœh˜hKšœ3˜3Kšœœ˜Lšœ˜Lšœ˜—Mšœ4œœ˜BKšœ=˜=Kšœ/˜/KšœŸ˜—š  œœœ+œœœ˜vK™eKšœœ ˜šœœ˜Kšœœœœ œœœœ˜DLšœh˜hKšœ3˜3Kšœœ˜Lšœ˜Lšœ˜—Mšœ2˜2KšœŸ˜—š   œœœ%œœ˜NKšœ*Οeœ‘œ+™tKšœ ˜ š  œ˜'Kšœœ$œœ™>Kšœ)˜)KšœŸ ˜—Kš œ œœœœ œ˜GKšœœœ˜KšœQ˜QKšœ4˜4KšœŸ˜——™š œœ1œ ˜]Iabsolute™)KšœV˜\KšœŸ˜—Lšœ œœ0˜Eš   œœBœœœ˜yKšœ4™4Kšœœœœ˜#šœ ˜šœ˜$Kšœ'œ ˜:šœœœ˜'KšœL˜LKšœIœœœ˜^Kš˜—Kšœ˜—Kšœœ˜Kšœ˜Kšœ˜—KšœŸ˜—š  œ ˜Kšœ.™.šœ ˜šœ˜$Kšœ'œ ˜:šœœœ˜.šœœœ˜KšœM˜M—Kš˜—Kšœ˜—šœ"˜"šœœœ˜(šœœœ˜KšœG˜G—Kš˜——KšœœŸ˜ —KšœŸ ˜—š  œœ;˜Oš  œ"˜0Kšœœœœ™0KšœE˜EKšœ˜Kšœ˜š  œ˜'Kšœœ$œœ™>KšœI™Išœ œ˜Kšœ œœœ5˜Zšœ˜Kšœ œ ˜Kšœ3˜3Kš˜——KšœŸ ˜—Mšœœœ˜+Kšœ-œ™:šœ˜)šœ œ˜/KšœJ˜J—Kšœ$Οtœ˜*Kšœ>˜E—KšœŸ ˜—Mšœ7˜7šœœœ˜KšœB˜BKš˜—KšœŸ ˜——™Lšœœ˜0Kšœ!˜!Kšœ+˜+š œœ˜%K™.Kšœ$œ ˜GKšœ$œ ˜GKšœ,˜,KšœWœ˜]KšœR˜RKšœU˜UKšœX˜XMšœ/˜/Kšœ0˜0Kšœ1˜1Kšœ4˜4šœœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜KšœQ˜QKšœ˜Kšœ˜—Mšœ˜Kšœ˜KšœX˜XMšœ œ%˜/Kšœ œ&˜0KšœŸ˜—š œœ6œ˜lKšœI™IKšœ˜šœœ˜Kšœ'˜'Kšœœœœ˜EKšœ œœœ˜>Kšœ œ˜Kšœœ˜Kšœ˜Kšœœ˜Kšœ ˜ —Kšœ˜Kšœ.˜.KšœŸ˜—š œ˜&Kš œ.œ œœœœ™\KšŸΧΠckŸίœŸ'£Ÿ#™–Lšœœ ˜"š  œœœœ˜>LšœQ™Qšœ œ!œ˜8Kšœ9˜9Kš˜—KšœŸ˜—š  œœœ˜1K™]Kšœœ˜,Kšœœ(˜:š œ œ œ œœœ˜WK™\Kšœ œ œ œ˜QKšœ˜Kšœ˜Kš˜—KšœŸ˜—š œœ$œ˜DK™˜>Kšœ˜KšœZ˜ZKš˜—KšœŸ ˜—š  œ˜&Kšœœ œ™ Kšœ œ˜Kšœ"Ÿ#˜EMšœœœ˜Kšœ˜Kšœ&˜&KšœŸ ˜—š œ˜-Kšœœ œ™ Kšœ"Ÿ#˜EKšœœ˜Mšœœœ˜Kšœ˜Kšœ'˜'Kšœ˜Kšœ˜Kšœ.Ÿ˜6Kšœ.Ÿ˜5Kšœ.Ÿ˜6Kšœ.Ÿ˜5Mšœœœ˜*Kšœ˜Kšœœœ ˜)KšœŸ˜—Mšœœ˜1Kšœœ˜8Kšœ3Ÿ˜Lš œœœœ œ˜UKšœœœœ ™FKšœ˜Kšœ$˜$Kšœ˜—Mš œœœœœ˜;Mšœœ˜%šœœœŸ)˜KKšœ?˜?KšœœR˜cKšœ˜Kšœ˜—KšœE˜EKšœ3Ÿ˜LKšœ%˜%KšœZ˜ZKšœ%˜%šœ˜˜ Kšœb˜b—˜ Kšœf˜f—Kšœ˜—KšœŸ˜ —š œ˜5Kšœ%œœœœœœœ™zKšœ#™#KšŸXΟz Ÿ€ΠczŸ-¦ ŸΑ™κLšœœ ˜"Lšœ™šœœ˜šœ˜šœ ˜K™eKšœœœΠbk˜:Kšœ˜—šœœ*œ˜K™1Kšœœ˜*Kšœ˜KšœY˜YKšœ;˜;Kšœ˜—šœ œŸ˜"Kšœœ˜Kšœ-˜-Kšœ˜—šœœŸ˜Kš œœœœœ˜=KšœR˜RKšœ˜Kšœ<˜˜>Kšœ˜—Kšœ8˜8Kšœ1˜1Kš˜—Kš˜—Kšœœ˜—KšœŸ˜—š œœ˜K™MKšœ%˜%KšœŸ˜—š  œœœœ˜5Kšœœœ™šœ˜ Kšœœ œ˜DKš˜—KšœŸ˜ —š  œœœœ˜;Lšœ™Kšœœ"œ˜OKšœ˜KšœŸ˜ ——™ š  œœ œ˜6Kšœœ$˜,Kšœœ$˜,Kšœ?˜EKšœŸ ˜—š   œœœ œ œ˜=Kšœ˜!KšœŸ ˜—š  œœ œœœ ™9Kšœ™!KšœŸ™ —š   œœ œœœ˜LKšœ ‘ œ™3šœ ˜KšœS˜SKšœ˜—Kšœ˜ KšœŸ˜—š œœœ˜*Kšœ^œ™{KšœJ˜JKšœŸ˜—š œœœ˜ Kšœ.œœ ˜DKšœŸ˜ ——™Lšœ˜—Lšœ˜™!K™’Kšœ Οr ™—™!K™%Kšœ ¨"œ¨œ¨œ¨ œ¨ œ¨ œ¨ œ¨œ¨ œ¨ ™°—™ K™(K™ΏKšœ ¨G™S—™ K™7Kšœ ¨:™F—K™—…—a œ: