DIRECTORY Carets, CaretsImpl, CGArea, CGContext, CGDevice, CGMatrix, CGPath, CGSource, Graphics, GraphicsBasic, GraphicsOps, NewerBottom, Process, Real, RealFns, VFonts, ViewerClasses, ViewerOps, ViewerPaintImpl; NewerBottomImpl: CEDAR MONITOR IMPORTS Carets, CaretsImpl, CGMatrix, CGPath, Graphics, GraphicsOps, Process, Real, RealFns, VFonts, ViewerOps, ViewerPaintImpl EXPORTS NewerBottom SHARES CaretsImpl, ViewerOps, ViewerPaintImpl = BEGIN OPEN NewerBottom; Area: TYPE = CGArea.Ref; Color: TYPE = Graphics.Color; ContextData: TYPE = CGContext.Ref; Device: TYPE = CGDevice.Ref; FontRef: TYPE = Graphics.FontRef; ImageRef: TYPE = Graphics.ImageRef; Mark: TYPE = Graphics.Mark; Matrix: TYPE = CGMatrix.Ref; PaintMode: TYPE = Graphics.PaintMode; PaintVector: TYPE = ViewerPaintImpl.PaintVector; Source: TYPE = CGSource.Ref; StrokeEnds: TYPE = Graphics.StrokeEnds; Viewer: TYPE = ViewerClasses.Viewer; XYWH: TYPE = RECORD [x, y, w, h: INT]; Replace: PUBLIC PROC [conser: Conser, paint: BOOL _ TRUE] = BEGIN ENABLE UNWIND => {ViewerOps.EnablePainting[]; Carets.ResumeCarets[]}; pv: PaintVector; screen: Context; Carets.SuspendCarets[]; ViewerOps.DisablePainting[]; [] _ (screen _ conser.Cons[conser.arg]).SetPaintMode[invert]; TRUSTED { CaretsImpl.screen _ screen; pv _ ViewerPaintImpl.vectorRoot}; FOR pv _ pv, pv.next WHILE pv # NIL DO pv.context _ conser.Cons[conser.arg]; pv.context.SetDefaultFont[VFonts.defaultGFont]; pv.viewer _ NIL; ENDLOOP; ViewerOps.EnablePainting[]; Carets.ResumeCarets[]; IF paint THEN ViewerOps.PaintEverything[]; END; Vanillify: PUBLIC PROC [paint: BOOL _ TRUE] = {Replace[vanillaConser, paint]}; vanillaConser: Conser _ NEW [ConserRep _ [ConsVanilla, NIL]]; ConsVanilla: PROC [arg: REF ANY] RETURNS [context: Context] = {context _ Graphics.NewContext[]}; XFormer: TYPE = REF XFormerData; XFormerData: TYPE = RECORD [ under: Context, xform, altxform: Transform, deviceClipBox: Box, clipped: BOOL, deviceB: Bitmap, bufferB: Bitmap, bufferC: Context]; worldToScreen, screenToWorld: Matrix; xformerProcs: REF Graphics.GraphicsProcs _ NEW [Graphics.GraphicsProcs _ [ GetCP: XFormerGetCP, SetCP: XFormerSetCP, DrawTo: XFormerDrawTo, DrawStroke: XFormerDrawStroke, DrawArea: XFormerDrawArea, DrawBox: XFormerDrawBox, DrawImage: XFormerDrawImage, Translate: XFormerTranslate, Concat: XFormerConcat, WorldToUser: XFormerWorldToUser, UserToWorld: XFormerUserToWorld, SetColor: XFormerSetColor, GetColor: XFormerGetColor, SetPaintMode: XFormerSetPaintMode, SetFat: XFormerSetFat, GetDefaultFont: XFormerGetDefaultFont, SetDefaultFont: XFormerSetDefaultFont, DrawChars: XFormerDrawChars, ClipArea: XFormerClipArea, ClipBox: XFormerClipBox, IsPointVisible: XFormerIsPointVisible, IsRectangular: XFormerIsRectangular, GetBounds: XFormerGetBounds, Visible: XFormerVisible, Save: XFormerSave, Restore: XFormerRestore, DrawBits: XFormerDrawBits, UserToDevice: XFormerUserToDevice, DeviceToUser: XFormerDeviceToUser, GetYMode: XFormerGetYMode, SetYMode: XFormerSetYMode, DrawTexturedBox: XFormerDrawTexturedBox, Disable: XFormerDisable, MoveDeviceRectangle: XFormerMoveDeviceRectangle ]]; Circle: PUBLIC PROC [x, y, r: REAL] RETURNS [p: Path] = { a: REAL _ r * (RealFns.SqRt[2] - 1.0) * 4.0 / 3.0; p _ Graphics.NewPath[]; Graphics.MoveTo[p, x+r, y]; Graphics.CurveTo[p, x+r, y+a, x+a, y+r, x, y+r]; Graphics.CurveTo[p, x-a, y+r, x-r, y+a, x-r, y]; Graphics.CurveTo[p, x-r, y-a, x-a, y-r, x, y-r]; Graphics.CurveTo[p, x+a, y-r, x+r, y-a, x+r, y]; }; DoXFormer: PUBLIC PROC [xfa: XFormArgRep, paint: BOOL _ TRUE] = { xfa.screenB _ GraphicsOps.ScreenBitmap[]; xfa.bufferB _ GraphicsOps.NewBitmap[width: xfa.screenB.width, height: xfa.screenB.height]; Replace[ NEW [ConserRep _ [Cons: ConsXFormer, arg: NEW [XFormArgRep _ xfa]]], paint]}; ConsXFormer: PROC [arg: REF ANY] RETURNS [context: Context] = BEGIN xfa: XFormArg _ NARROW[arg]; under: Context _ Graphics.NewContext[]; userClipBox: Box _ IF xfa.clipByBox THEN xfa.clipBox ELSE IF xfa.clipByPath THEN CGPath.Bounds[xfa.clipPath] ELSE [0, 0, 0, 0]; deviceClipBox: Box _ UserBoxToDevice[under, userClipBox]; context _ NEW [Graphics.ContextRep _ [ procs: xformerProcs, data: NEW [XFormerData _ [ under: under, xform: xfa.t, altxform: Mult[screenToWorld.m, Mult[xfa.t, worldToScreen.m]], deviceClipBox: deviceClipBox, clipped: xfa.clipByBox OR xfa.clipByPath, deviceB: xfa.screenB, bufferB: xfa.bufferB, bufferC: GraphicsOps.NewContextFromBitmap[xfa.bufferB] ]] ]]; IF xfa.clipByBox THEN Graphics.ClipBox[under, xfa.clipBox, TRUE] ELSE IF xfa.clipByPath THEN Graphics.ClipArea[under, xfa.clipPath, FALSE, TRUE]; AppendTransform[under, xfa.t]; END; UserBoxToDevice: PROC [context: Context, user: Box] RETURNS [device: Box] = { x1, y1, x2, y2: REAL; [x1, y1] _ GraphicsOps.UserToDevice[context, user.xmin, user.ymin]; [x2, y2] _ GraphicsOps.UserToDevice[context, user.xmax, user.ymax]; device _ [ xmin: MIN[x1, x2], xmax: MAX[x1, x2], ymin: MIN[y1, y2], ymax: MAX[y1, y2]]; }; AppendTransform: PROC [context: Context, t: Transform] = { context.Translate[t.e, t.f]; context.Concat[t.a, t.b, t.c, t.d]}; XFormerGetCP: PROC[self: Context, rounded: BOOLEAN] RETURNS[x,y: REAL] = BEGIN xf: XFormer _ NARROW[self.data]; [x: x, y: y] _ xf.under.procs.GetCP[self: xf.under, rounded: rounded]; END; XFormerSetCP: PROC[self: Context, x,y: REAL, rel: BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.SetCP[self: xf.under, x: x, y: y, rel: rel]; END; XFormerDrawTo: PROC[self: Context, x,y: REAL, rel: BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.DrawTo[self: xf.under, x: x, y: y, rel: rel]; END; XFormerDrawStroke: PROC[self: Context, path: Path, width: REAL, closed: BOOLEAN, ends: StrokeEnds] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.DrawStroke[self: xf.under, path: path, width: width, closed: closed, ends: ends]; END; XFormerDrawArea: PROC[self: Context, path: Path, parityFill: BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.DrawArea[self: xf.under, path: path, parityFill: parityFill]; END; XFormerDrawBox: PROC[self: Context, box: Box] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.DrawBox[self: xf.under, box: box]; END; XFormerDrawImage: PROC[self: Context, image: ImageRef, raw: BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.DrawImage[self: xf.under, image: image, raw: raw]; END; XFormerTranslate: PROC[self: Context, tx,ty: REAL, round: BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.Translate[self: xf.under, tx: tx, ty: ty, round: round]; END; XFormerConcat: PROC[self: Context, m11,m12,m21,m22: REAL] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.Concat[self: xf.under, m11: m11, m12: m12, m21: m21, m22: m22]; END; XFormerWorldToUser: PROC[self: Context, wx,wy: REAL] RETURNS[x,y: REAL] = BEGIN xf: XFormer _ NARROW[self.data]; [x: x, y: y] _ xf.under.procs.WorldToUser[self: xf.under, wx: wx, wy: wy]; END; XFormerUserToWorld: PROC[self: Context, x,y: REAL] RETURNS[wx,wy: REAL] = BEGIN xf: XFormer _ NARROW[self.data]; [wx: wx, wy: wy] _ xf.under.procs.UserToWorld[self: xf.under, x: x, y: y]; END; XFormerSetColor: PROC[self: Context, color: Color] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.SetColor[self: xf.under, color: color]; END; XFormerGetColor: PROC[self: Context] RETURNS[Color] = BEGIN xf: XFormer _ NARROW[self.data]; RETURN [xf.under.procs.GetColor[self: xf.under]]; END; XFormerSetPaintMode: PROC[self: Context, mode: PaintMode] RETURNS[PaintMode] = BEGIN xf: XFormer _ NARROW[self.data]; RETURN [xf.under.procs.SetPaintMode[self: xf.under, mode: mode]]; END; XFormerSetFat: PROC[self: Context, fat: BOOLEAN] RETURNS[BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; RETURN [xf.under.procs.SetFat[self: xf.under, fat: fat]]; END; XFormerGetDefaultFont: PROC[self: Context] RETURNS[FontRef] = BEGIN xf: XFormer _ NARROW[self.data]; RETURN [xf.under.procs.GetDefaultFont[self: xf.under]]; END; XFormerSetDefaultFont: PROC[self: Context, font: FontRef] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.SetDefaultFont[self: xf.under, font: font]; END; XFormerDrawChars: PROC[self: Context, font: FontRef, map: PROC[PROC[CHAR] RETURNS[BOOL]]] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.DrawChars[self: xf.under, font: font, map: map]; END; XFormerClipArea: PROC[self: Context, path: Path, parityFill: BOOLEAN, exclude: BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.ClipArea[self: xf.under, path: path, parityFill: parityFill, exclude: exclude]; END; XFormerClipBox: PROC[self: Context, box: Box, exclude: BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.ClipBox[self: xf.under, box: box, exclude: exclude]; END; XFormerIsPointVisible: PROC[self: Context, x,y: REAL] RETURNS[BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; RETURN [xf.under.procs.IsPointVisible[self: xf.under, x: x, y: y]]; END; XFormerIsRectangular: PROC[self: Context] RETURNS[BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; RETURN [xf.under.procs.IsRectangular[self: xf.under]]; END; XFormerGetBounds: PROC[self: Context] RETURNS[Box] = BEGIN xf: XFormer _ NARROW[self.data]; RETURN [xf.under.procs.GetBounds[self: xf.under]]; END; XFormerVisible: PROC[self: Context] RETURNS[BOOLEAN] = BEGIN xf: XFormer _ NARROW[self.data]; RETURN [xf.under.procs.Visible[self: xf.under]]; END; XFormerSave: PROC[self: Context] RETURNS[Mark] = BEGIN xf: XFormer _ NARROW[self.data]; RETURN [xf.under.procs.Save[self: xf.under]]; END; XFormerRestore: PROC[self: Context, mark: Mark] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.Restore[self: xf.under, mark: mark]; END; XFormerDrawBits: UNSAFE PROC[self: Context, base: LONG POINTER, raster: CARDINAL, bitsPerPixel: [0..16), x, y, w, h: CARDINAL, xorigin, yorigin: INTEGER] = TRUSTED BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.DrawBits[self: xf.under, base: base, raster: raster, bitsPerPixel: bitsPerPixel, x: x, y: y, w: w, h: h, xorigin: xorigin, yorigin: yorigin]; END; XFormerUserToDevice: PROC[self: Context, x, y: REAL, rel: BOOLEAN] RETURNS[tx, ty: REAL] = BEGIN xf: XFormer _ NARROW[self.data]; [tx, ty] _ xf.under.procs.UserToDevice[self: xf.under, x: x, y: y, rel: rel]; END; XFormerDeviceToUser: PROC[self: Context, tx, ty: REAL, rel: BOOLEAN] RETURNS[x, y: REAL] = BEGIN xf: XFormer _ NARROW[self.data]; [x, y] _ xf.under.procs.DeviceToUser[self: xf.under, tx: tx, ty: ty, rel: rel]; END; XFormerGetYMode: PROC[self: Context] RETURNS[GraphicsBasic.YMode] = BEGIN xf: XFormer _ NARROW[self.data]; RETURN [xf.under.procs.GetYMode[self: xf.under]]; END; XFormerSetYMode: PROC[self: Context, mode: GraphicsBasic.YMode] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.SetYMode[self: xf.under, mode: mode]; END; XFormerDrawTexturedBox: PROC[self: Context, box: Box, texture: GraphicsBasic.Texture] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.DrawTexturedBox[self: xf.under, box: box, texture: texture]; END; XFormerDisable: PROC[self: Context] = BEGIN xf: XFormer _ NARROW[self.data]; xf.under.procs.Disable[self: xf.under]; END; lastXF: XFormer _ NIL; lastTo: XYWH _ [0, 0, 0, 0]; lastIntersected: BOOL _ FALSE; forceDumb: BOOL _ FALSE; XFormerMoveDeviceRectangle: PROC [self: Context, width, height, fromX, fromY, toX, toY: NAT] = BEGIN xf: XFormer _ NARROW[self.data]; from, to: XYWH; from _ Xform[xf.altxform, [x: fromX, y: fromY, w: width, h: height]]; to _ Xform[xf.altxform, [x: toX, y: toY, w: width, h: height]]; [from.x, to.x, from.w, to.w] _ Clip[from.x, to.x, from.w, to.w]; [from.y, to.y, from.h, to.h] _ Clip[from.y, to.y, from.h, to.h]; lastXF _ xf; lastTo _ to; IF xf.clipped AND (lastIntersected _ Intersect[xf.deviceClipBox, to]) AND NOT forceDumb THEN { bcX, bcY, scpX, scpY, scX, scY: REAL; [bcX, bcY] _ GraphicsOps.DeviceToUser[xf.bufferC, from.x, from.y]; Graphics.SetCP[xf.bufferC, bcX, bcY]; GraphicsOps.DrawBitmap[ self: xf.bufferC, bitmap: xf.deviceB, w: from.w, h: from.h, x: from.x, y: from.y, xorigin: from.x, yorigin: from.y]; [scpX, scpY] _ Graphics.GetCP[xf.under]; [scX, scY] _ GraphicsOps.DeviceToUser[xf.under, to.x, to.y]; Graphics.SetCP[xf.under, scX, scY]; GraphicsOps.DrawBitmap[ self: xf.under, bitmap: xf.bufferB, w: from.w, h: from.h, x: from.x, y: from.y, xorigin: from.x, yorigin: from.y]; Graphics.SetCP[xf.under, scpX, scpY]; } ELSE xf.under.procs.MoveDeviceRectangle[self: xf.under, width: from.w, height: from.h, fromX: from.x, fromY: from.y, toX: to.x, toY: to.y]; lastTo _ to; END; Xform: PROC [altXform: Transform, old: XYWH] RETURNS [new: XYWH] = BEGIN Map: PROC [x, y: INT] RETURNS [X, Y: INT] = { OPEN altXform; X _ Real.RoundLI[a*x + c*y + e]; Y _ Real.RoundLI[b*x + d*y + f]; }; Cannonize: PROC [z1, z2: INT] RETURNS [min, diff: INT] = { min _ MIN[z1, z2]; diff _ ABS[z1-z2]; }; x1, x2, y1, y2: INT; [x1, y1] _ Map[old.x, old.y]; [x2, y2] _ Map[old.x + old.w, old.y + old.h]; [new.x, new.w] _ Cannonize[x1, x2]; [new.y, new.h] _ Cannonize[y1, y2]; END; Clip: PROC [x1, x2, w1, w2: INT] RETURNS [x1a, x2a, w1a, w2a: INT] = { diff: INT _ 0 - MIN[x1, x2]; IF diff <= 0 THEN RETURN [x1, x2, w1, w2]; IF diff >= w1 OR diff >= w2 THEN RETURN [0, 0, 0, 0]; RETURN [x1+diff, x2+diff, w1-diff, w2-diff]; }; Intersect: PROC [box: Box, xywh: XYWH] RETURNS [b: BOOL] = {b _ (box.xmax > xywh.x) AND (xywh.x+xywh.w > box.xmin) AND (box.ymax > xywh.y) AND (xywh.y+xywh.h > box.ymin)}; Mult: PROC [left, right: Transform] RETURNS [ans: Transform] = { ans _ [ a: left.a*right.a + left.b*right.c, b: left.a*right.b + left.b*right.d, c: left.c*right.a + left.d*right.c, d: left.c*right.b + left.d*right.d, e: left.e*right.a + left.f*right.c + right.e, f: left.e*right.b + left.f*right.d + right.f]}; Forker: TYPE = REF ForkerRep; ForkerRep: TYPE = RECORD [ subs: ContextList _ NIL, next: CARDINAL _ 1, marks: ForkerMark _ NIL]; ContextList: TYPE = LIST OF Context; forkerProcs: REF Graphics.GraphicsProcs _ NEW [Graphics.GraphicsProcs _ [ GetCP: ForkerGetCP, SetCP: ForkerSetCP, DrawTo: ForkerDrawTo, DrawStroke: ForkerDrawStroke, DrawArea: ForkerDrawArea, DrawBox: ForkerDrawBox, DrawImage: ForkerDrawImage, Translate: ForkerTranslate, Concat: ForkerConcat, WorldToUser: ForkerWorldToUser, UserToWorld: ForkerUserToWorld, SetColor: ForkerSetColor, GetColor: ForkerGetColor, SetPaintMode: ForkerSetPaintMode, SetFat: ForkerSetFat, GetDefaultFont: ForkerGetDefaultFont, SetDefaultFont: ForkerSetDefaultFont, DrawChars: ForkerDrawChars, ClipArea: ForkerClipArea, ClipBox: ForkerClipBox, IsPointVisible: ForkerIsPointVisible, IsRectangular: ForkerIsRectangular, GetBounds: ForkerGetBounds, Visible: ForkerVisible, Save: ForkerSave, Restore: ForkerRestore, DrawBits: ForkerDrawBits, UserToDevice: ForkerUserToDevice, DeviceToUser: ForkerDeviceToUser, GetYMode: ForkerGetYMode, SetYMode: ForkerSetYMode, DrawTexturedBox: ForkerDrawTexturedBox, Disable: ForkerDisable, MoveDeviceRectangle: ForkerMoveDeviceRectangle ]]; ConsForker: PROC [arg: REF ANY] RETURNS [context: Context] = BEGIN consers: LIST OF REF ANY _ NARROW[arg]; f: Forker _ NEW [ForkerRep _ []]; context _ NEW [Graphics.ContextRep _ [ procs: forkerProcs, data: f]]; FOR consers _ consers, consers.rest WHILE consers # NIL DO conser: Conser _ NARROW[consers.first]; f.subs _ CONS[conser.Cons[conser.arg], f.subs]; f.subs.first.SetCP[0, 0]; ENDLOOP; END; ForkerGetCP: PROC[self: Context, rounded: BOOLEAN] RETURNS[x,y: REAL] = BEGIN f: Forker _ NARROW[self.data]; [x, y] _ f.subs.first.procs.GetCP[self: f.subs.first, rounded: rounded]; END; ForkerSetCP: PROC[self: Context, x,y: REAL, rel: BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.SetCP[self: c.first, x: x,y: y, rel: rel]; ENDLOOP; END; ForkerDrawTo: PROC[self: Context, x,y: REAL, rel: BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.DrawTo[self: c.first, x: x,y: y, rel: rel]; ENDLOOP; END; ForkerDrawStroke: PROC[self: Context, path: Path, width: REAL, closed: BOOLEAN, ends: StrokeEnds] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.DrawStroke[self: c.first, path: path, width: width, closed: closed, ends: ends]; ENDLOOP; END; ForkerDrawArea: PROC[self: Context, path: Path, parityFill: BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.DrawArea[self: c.first, path: path, parityFill: parityFill]; ENDLOOP; END; ForkerDrawBox: PROC[self: Context, box: Box] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.DrawBox[self: c.first, box: box]; ENDLOOP; END; ForkerDrawImage: PROC[self: Context, image: ImageRef, raw: BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.DrawImage[self: c.first, image: image, raw: raw]; ENDLOOP; END; ForkerTranslate: PROC[self: Context, tx,ty: REAL, round: BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.Translate[self: c.first, tx: tx,ty: ty, round: round]; ENDLOOP; END; ForkerConcat: PROC[self: Context, m11, m12, m21, m22: REAL] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.Concat[self: c.first, m11: m11, m12: m12, m21: m21, m22: m22]; ENDLOOP; END; ForkerWorldToUser: PROC[self: Context, wx, wy: REAL] RETURNS[x, y: REAL] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO [x, y] _ c.first.procs.WorldToUser[self: c.first, wx: wx, wy: wy]; ENDLOOP; END; ForkerUserToWorld: PROC[self: Context, x, y: REAL] RETURNS[wx, wy: REAL] = BEGIN f: Forker _ NARROW[self.data]; [wx, wy] _ f.subs.first.procs.UserToWorld[self: f.subs.first, x: x, y: y]; END; ForkerSetColor: PROC[self: Context, color: Color] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.SetColor[self: c.first, color: color]; ENDLOOP; END; ForkerGetColor: PROC[self: Context] RETURNS[Color] = BEGIN f: Forker _ NARROW[self.data]; RETURN [f.subs.first.procs.GetColor[self: f.subs.first]]; END; ForkerSetPaintMode: PROC[self: Context, mode: PaintMode] RETURNS[was: PaintMode] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO was _ c.first.procs.SetPaintMode[self: c.first, mode: mode]; ENDLOOP; END; ForkerSetFat: PROC[self: Context, fat: BOOLEAN] RETURNS[was: BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO was _ c.first.procs.SetFat[self: c.first, fat: fat]; ENDLOOP; END; ForkerGetDefaultFont: PROC[self: Context] RETURNS[FontRef] = BEGIN f: Forker _ NARROW[self.data]; RETURN [f.subs.first.procs.GetDefaultFont[self: f.subs.first]]; END; ForkerSetDefaultFont: PROC[self: Context, font: FontRef] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.SetDefaultFont[self: c.first, font: font]; ENDLOOP; END; ForkerDrawChars: PROC[self: Context, font: FontRef, map: PROC[PROC[CHAR] RETURNS[BOOL]]] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.DrawChars[self: c.first, font: font, map: map]; ENDLOOP; END; ForkerClipArea: PROC[self: Context, path: Path, parityFill: BOOLEAN, exclude: BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.ClipArea[self: c.first, path: path, parityFill: parityFill, exclude: exclude]; ENDLOOP; END; ForkerClipBox: PROC[self: Context, box: Box, exclude: BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.ClipBox[self: c.first, box: box, exclude: exclude]; ENDLOOP; END; ForkerIsPointVisible: PROC[self: Context, x,y: REAL] RETURNS[BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; RETURN [f.subs.first.procs.IsPointVisible[self: f.subs.first, x: x,y: y]]; END; ForkerIsRectangular: PROC[self: Context] RETURNS[BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; RETURN [f.subs.first.procs.IsRectangular[self: f.subs.first]]; END; ForkerGetBounds: PROC[self: Context] RETURNS[Box] = BEGIN f: Forker _ NARROW[self.data]; RETURN [f.subs.first.procs.GetBounds[self: f.subs.first]]; END; ForkerVisible: PROC[self: Context] RETURNS[BOOLEAN] = BEGIN f: Forker _ NARROW[self.data]; RETURN [f.subs.first.procs.Visible[self: f.subs.first]]; END; ForkerMark: TYPE = REF ForkerMarkRep; ForkerMarkRep: TYPE = RECORD [ mark: Mark, subs: SaveList, prev: ForkerMark]; SaveList: TYPE = LIST OF SaveRep; SaveRep: TYPE = RECORD [ context: Context, mark: Mark]; ForkerSave: PROC[self: Context] RETURNS[mark: Mark] = BEGIN f: Forker _ NARROW[self.data]; f.marks _ NEW [ForkerMarkRep _ [ mark: mark _ [f.next], subs: NIL, prev: f.marks]]; f.next _ f.next + 1; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO f.marks.subs _ CONS[[c.first, c.first.procs.Save[self: c.first]], f.marks.subs]; ENDLOOP; END; ForkerRestore: PROC[self: Context, mark: Mark] = BEGIN f: Forker _ NARROW[self.data]; Pop: PROC = {--f.next _ f.marks.mark; --f.marks _ f.marks.prev}; IF mark = GraphicsBasic.nullMark THEN NULL ELSE WHILE (IF f.marks = NIL THEN FALSE ELSE (f.marks.mark # mark)) DO Pop[]; ENDLOOP; IF ((mark = GraphicsBasic.baseMark) # (f.marks = NIL)) OR errorTest THEN ERROR; IF f.marks = NIL THEN FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.Restore[self: c.first, mark: GraphicsBasic.baseMark]; ENDLOOP ELSE FOR s: SaveList _ f.marks.subs, s.rest WHILE s # NIL DO s.first.context.Restore[s.first.mark]; ENDLOOP; END; errorTest: BOOLEAN _ FALSE; ForkerDrawBits: UNSAFE PROC[self: Context, base: LONG POINTER, raster: CARDINAL, bitsPerPixel: [0..16), x, y, w, h: CARDINAL, xorigin, yorigin: INTEGER] = TRUSTED BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.DrawBits[self: c.first, base: base, raster: raster, bitsPerPixel: bitsPerPixel, x: x, y: y, w: w, h: h, xorigin: xorigin, yorigin: yorigin]; ENDLOOP; END; ForkerUserToDevice: PROC[self: Context, x, y: REAL, rel: BOOLEAN] RETURNS[tx, ty: REAL] = BEGIN f: Forker _ NARROW[self.data]; [tx, ty] _ f.subs.first.procs.UserToDevice[self: f.subs.first, x: x, y: y, rel: rel]; END; ForkerDeviceToUser: PROC[self: Context, tx, ty: REAL, rel: BOOLEAN] RETURNS[x, y: REAL] = BEGIN f: Forker _ NARROW[self.data]; [x, y] _ f.subs.first.procs.DeviceToUser[self: f.subs.first, tx: tx, ty: ty, rel: rel]; END; ForkerGetYMode: PROC[self: Context] RETURNS[GraphicsBasic.YMode] = BEGIN f: Forker _ NARROW[self.data]; RETURN [f.subs.first.procs.GetYMode[self: f.subs.first]]; END; ForkerSetYMode: PROC[self: Context, mode: GraphicsBasic.YMode] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.SetYMode[self: c.first, mode: mode]; ENDLOOP; END; ForkerDrawTexturedBox: PROC[self: Context, box: Box, texture: GraphicsBasic.Texture] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.DrawTexturedBox[self: c.first, box: box, texture: texture]; ENDLOOP; END; ForkerDisable: PROC[self: Context] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.Disable[self: c.first]; ENDLOOP; END; ForkerMoveDeviceRectangle: PROC[self: Context, width, height, fromX, fromY, toX, toY: NAT] = BEGIN f: Forker _ NARROW[self.data]; FOR c: ContextList _ f.subs, c.rest WHILE c # NIL DO c.first.procs.MoveDeviceRectangle[self: c.first, width: width, height: height, fromX: fromX, fromY: fromY, toX: toX, toY: toY]; ENDLOOP; END; Feedbacker: TYPE = REF FeedbackerRep; FeedbackerRep: TYPE = RECORD [ xmin, ymin, dx, dy: INT _ -1, screenToView: Transform _ [1, 0, 0, 1, 0, 0]]; screenBitmap: GraphicsOps.BitmapRef; PaintFeedbacker: ViewerClasses.PaintProc--PROC [self: Viewer, context: Graphics.Context, whatChanged: REF ANY, clear: BOOL]-- = BEGIN fb: Feedbacker _ NARROW[self.data]; News: ENTRY PROC RETURNS [news: BOOLEAN] = BEGIN IF self.cw = fb.dx AND self.ch = fb.dy THEN BEGIN xmin, ymin: INTEGER; [xmin, ymin] _ ViewerOps.UserToScreenCoords[self, 0, 0]; IF xmin = fb.xmin AND ymin = fb.ymin THEN RETURN [FALSE]; fb.xmin _ xmin; fb.ymin _ ymin; END ELSE BEGIN [fb.xmin, fb.ymin] _ ViewerOps.UserToScreenCoords[self, 0, 0]; fb.dx _ self.cw; fb.dy _ self.ch; END; news _ TRUE; END; IF self.iconic THEN RETURN ELSE IF News[] THEN TRUSTED {Process.Detach[FORK Adjust[self, fb]]} ELSE IF clear THEN BEGIN AppendTransform[context, [ fb.screenToView.a, 0, 0, fb.screenToView.d, fb.screenToView.e - fb.xmin, fb.screenToView.f - fb.ymin]]; context.SetCP[0, 0]; GraphicsOps.DrawBitmap[self: context, bitmap: screenBitmap, w: screenBitmap.width, h: screenBitmap.height, x: 0, y: 0, xorigin: 0, yorigin: screenBitmap.height]; END; END; Adjust: PROC [v: Viewer, fb: Feedbacker] = BEGIN scale: REAL _ MIN[REAL[fb.dx]/screenBitmap.width, REAL[fb.dy]/screenBitmap.height]; fb.screenToView.b _ fb.screenToView.c _ 0; fb.screenToView.a _ fb.screenToView.d _ scale; fb.screenToView.e _ (fb.xmin + fb.dx/2.0) - scale*(screenBitmap.width/2.0); fb.screenToView.f _ (fb.ymin + fb.dy/2.0) - scale*(screenBitmap.height/2.0); Replace[NEW [ConserRep _ [ ConsForker, LIST[ NEW [ConserRep _ [ConsXFormer, NEW [Transform _ Mult[fb.screenToView, fb.screenToView]] ]], NEW [ConserRep _ [ConsXFormer, NEW [Transform _ fb.screenToView]]], vanillaConser ] ]] ]; END; MakeFeedbacker: PROC = BEGIN it _ ViewerOps.CreateViewer[ flavor: $Feedbacker, info: [ data: NEW [FeedbackerRep _ []], name: "Feedbacker", iconic: TRUE], paint: TRUE]; END; it: Viewer _ NIL; feedbacker: ViewerClasses.ViewerClass _ NEW [ViewerClasses.ViewerClassRec _ [ flavor: $Feedbacker, paint: PaintFeedbacker]]; Setup: PROC = BEGIN screen: Context _ Graphics.NewContext[]; screenContextData: ContextData; screenContextData _ NARROW[screen.data]; worldToScreen _ screenContextData.device.GetMatrix[screenContextData.device]; screenToWorld _ CGMatrix.Copy[worldToScreen]; CGMatrix.Invert[screenToWorld]; screenBitmap _ GraphicsOps.ScreenBitmap[]; ViewerOps.RegisterViewerClass[flavor: $Feedbacker, class: feedbacker]; END; Setup[]; END. TNewerBottomImpl.Mesa Last Edited by: Spreitzer, March 31, 1985 5:31:09 pm PST Κέ– "cedar" style˜J™Jšœ8™8J˜IcodešΟk œΛ˜ΤK˜šΠbxœœ˜Kšœx˜Kšœ ˜Kšœ)˜/—K˜Kšœœ ˜K˜Kšœœ˜Kšœœ˜Kšœ œ˜"Kšœœ˜Kšœ œ˜!Kšœ œ˜#Kšœœ˜Kšœœ˜Kšœ œ˜%Kšœ œ˜0Kšœœ˜Kšœ œ˜'Kšœœ˜$K˜Kšœœœœ˜&K˜š Οnœœœœœ˜;šœœœ˜Kšœ4˜4—K˜Kšœ˜K˜Kšœ˜Kšœ=˜=šœ˜ Kšœ˜Kšœ!˜!—šœœœ˜&Kšœ%˜%Kšœ/˜/Kšœ œ˜Kšœ˜—Kšœ˜Kšœ˜Kšœœ˜*Kšœ˜—K˜š Ÿ œœœ œœ˜-Kšœ ˜ —K˜Kšœœœ˜=K˜š Ÿ œœœœœ˜=K˜"—K˜Kšœ œœ ˜ šœ œœ˜Kšœ˜K˜K˜Kšœ œ˜K˜Kšœ˜Kšœ˜—K˜Kšœ%˜%K˜šœœœ˜JKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ"˜"Kšœ˜Kšœ&˜&Kšœ&˜&Kšœ˜Kšœ˜Kšœ˜Kšœ&˜&Kšœ$˜$Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ"˜"Kšœ"˜"Kšœ˜Kšœ˜Kšœ(˜(Kšœ˜Kšœ/˜/K˜—K˜š Ÿœœœ œœ˜9Kšœœ+˜2Kšœ˜Kšœ˜Kšœ0˜0Kšœ0˜0Kšœ0˜0Kšœ0˜0Kšœ˜—K˜š Ÿ œœœœœ˜AKšœ)˜)KšœZ˜Zšœ˜Kšœ'œ˜DKšœ˜——K˜š Ÿ œœœœœ˜=Kš˜Kšœœ˜Kšœ'˜'Kš œœœ œœœœ˜Kšœ9˜9šœ œ˜&Kšœ˜šœœ˜Kšœ ˜ K˜ Kšœ>˜>K˜Kšœœ˜)K˜K˜Kšœ6˜6K˜—K˜—Kšœœ&œ˜EKšœœ(œœ˜KKšœ˜Kšœ˜—K˜šŸœœœ˜MKšœœ˜K˜CK˜C˜ Kšœœ ˜Kšœœ ˜Kšœœ ˜Kšœœ ˜—K˜—K˜šŸœœ%˜:Kšœ˜Kšœ$˜$—K˜š Ÿ œœœœœ˜HKš˜Kšœœ ˜ K˜FKšœ˜—K˜šŸ œœœœ˜Kšœ˜—K˜šŸœœœ˜3Kš˜Kšœ œ ˜Kšœ4˜:Kšœ˜—K˜šŸ œœœœ˜5Kš˜Kšœ œ ˜Kšœ2˜8Kšœ˜—K˜Kšœ œœ˜%šœœœ˜K˜ K˜K˜—K˜Kšœ œœœ ˜!šœ œœ˜K˜K˜ —K˜šŸ œœœ˜5Kš˜Kšœ œ ˜šœ œ˜ K˜Kšœœ˜ K˜—K˜šœ!œœ˜4Kšœœ=˜PKšœ˜—Kšœ˜—K˜šŸ œœ˜0Kš˜Kšœ œ ˜KšŸœœΟcœ˜@Kšœœœ˜/š œœ œœœœ˜AK˜Kšœ˜—Kš œ/œœ œœ˜Oš œ œœœ!œœ˜JKšœC˜CKš˜—š œœ$œœ˜˜>K˜K˜Kšœ˜—Kšœœ˜ Kšœ˜—Kšœ œ˜Kš œœœœœ˜Cšœœ˜Kš˜˜K˜K˜K˜Kšœ˜—K˜˜%K˜K˜Kšœ˜K˜ Kšœ*˜*—Kšœ˜—Kšœ˜—K˜šŸœœ˜*Kš˜Kš œœœœœ˜SK˜*K˜.KšœK˜KKšœL˜Lšœœ˜Kšœ ˜ šœ˜šœ˜Kšœ9˜<—Kšœœ!˜CK˜ K˜——Kšœ˜—K˜šŸœœ˜Kš˜˜K˜˜Kšœœ˜K˜Kšœœ˜—Kšœœ˜ —Kšœ˜—K˜Kšœ œ˜K˜šœ(œ"˜MK˜K˜—K˜šŸœœ˜ Kš˜Kšœ(˜(Kšœ˜Kšœœ˜(KšœM˜MKšœ-˜-Kšœ˜Kšœ*˜*K˜FKšœ˜—K˜K˜K˜Kšœ˜—…—fό‡-