<> <> <> <> <> <<>> DIRECTORY <> Imager USING [Context, SetColor, ColorOperator, MaskRectangle, SetFont, SetStrokeWidth, SetStrokeEnd, SetStrokeJoint, MaskVector, Color, Font, SetXY, ShowChar, ShowRope, DoSaveAll, RotateT, Move], ImagerBackdoor USING [GetBounds], ImagerColor USING [ColorFromRGB], ImagerColorOperator USING [RGBLinearColorModel], ImagerDitheredDevice USING [ColorFromSpecialPixel], ImagerFont USING [Scale, Find, RopeWidth, FontBoundingBox], ImagerInterpress USING [Ref, Create, DeclareColorOperator, DeclareFont, DoPage, Close], Draw2d, <> Menus USING [Menu, CreateMenu, AppendMenuEntry, ReplaceMenuEntry, CreateEntry, MouseButton, MenuEntry], ViewerClasses USING [Viewer, ViewerRec, ViewerClass, ViewerClassRec, NotifyProc, PaintProc, ModifyProc, DestroyProc, ScrollProc, HScrollProc, AdjustProc], ViewerOps USING [CreateViewer, PaintViewer, RegisterViewerClass, DestroyViewer], TIPUser USING [InstantiateNewTIPTable ,TIPScreenCoords], Icons USING [NewIconFromFile], InputFocus USING [GetInputFocus, SetInputFocus], <> IO USING [PutFR, real], Convert USING [RopeFromInt], Vector2 USING [VEC], Rope USING [ROPE, Cat, Length, InlineFetch], Real USING [FixI, Fix], MessageWindow USING [Append], PlotGraph; PlotGraphImpl: CEDAR MONITOR IMPORTS Imager, ImagerColor, ImagerColorOperator, ImagerDitheredDevice, ImagerInterpress, ImagerFont, ImagerBackdoor, Draw2d, IO, Convert, Menus, MessageWindow, ViewerOps, TIPUser, InputFocus, Rope, Real, Icons EXPORTS PlotGraph ~ BEGIN OPEN PlotGraph; <> VEC: TYPE ~ Vector2.VEC; PlotList: TYPE ~ LIST OF Plot; AxisList: TYPE ~ LIST OF Axis; GraphList: TYPE ~ LIST OF Graph; Viewer: TYPE ~ ViewerClasses.Viewer; ViewerData: TYPE ~ REF ViewerDataRec; Color: TYPE ~ Imager.Color; ViewerDataRec: TYPE ~ RECORD [ plot: Plot, -- circular references... frozen: BOOLEAN _ FALSE,--the display is no longer refreshed by outside requests grid: BOOLEAN _ FALSE, --an oscilloscope grid is painted on the viewer (if axis are coherent) magOn: BOOL _ FALSE, --state of the magnifier xScale: REAL _ 0.125, --mag plot width / plot width xOr: REAL _ 0.0 --mag origin _ plot origin+ plot width*xOr ]; DrawPtData: TYPE ~ REF DrawPtDataRec; DrawPtDataRec: TYPE ~ RECORD [ window: Rectangle, plotOr: VEC, -- physical coordinates or: VEC, -- client coordinates prevPt: VEC, mult: VEC, context: Imager.Context, visible: BOOLEAN _ TRUE, firstPoint: BOOLEAN _ TRUE ]; <> CreatePlot: PUBLIC PROC [name: ROPE _ NIL] RETURNS [plot: Plot] ~ { <> plot _ NEW[PlotRec]; plot.name _ NEW[ROPE _ name]; plot.private _ NEW[PlotGraphPrivateRec]; CreatePlotViewer[plot]; }; CreatePlotViewer: PROC [plot: Plot] ~ { <> menu: Menus.Menu; viewerData: ViewerData _ NEW[ViewerDataRec]; plot.private _ NEW[PlotGraphPrivateRec]; viewerData.plot _ plot; menu _ Menus.CreateMenu[]; Menus.AppendMenuEntry[menu: menu, entry: resetEntry]; Menus.AppendMenuEntry[menu: menu, entry: magOffEntry]; Menus.AppendMenuEntry[menu: menu, entry: gratEntry]; Menus.AppendMenuEntry[menu: menu, entry: shotEntry]; Menus.AppendMenuEntry[menu: menu, entry: activeEntry]; Menus.AppendMenuEntry[menu: menu, entry: sizeXEntry]; Menus.AppendMenuEntry[menu: menu, entry: magSizeEntry]; Menus.AppendMenuEntry[menu: menu, entry: sizeYEntry]; plot.private.viewer _ ViewerOps.CreateViewer[ flavor: $PlotGViewer, info: [ name: plot.name^, menu: menu, iconic: TRUE, column: left, scrollable: TRUE, hscrollable: TRUE, border: TRUE, guardDestroy: TRUE, -- window menu guards destroy data: viewerData ] ]; }; CreateChild: PUBLIC PROC [mom: Plot] RETURNS [baby: Plot] ~ { <> tempAxis: AxisList; baby _ NEW[PlotRec _ mom^]; baby.name _ NEW[ROPE _ Rope.Cat[mom.name^, "+"]]; baby.axis _ LIST[NIL]; tempAxis _ baby.axis; FOR iAxisList: AxisList _ mom.axis, iAxisList.rest UNTIL iAxisList=NIL DO tempAxis.rest _ LIST[NEW[AxisRec _ iAxisList.first^]]; tempAxis _ tempAxis.rest; ENDLOOP; baby.axis _ baby.axis.rest; }; AwakeOthers: ENTRY PROC [plot: Plot] ~ { ENABLE UNWIND => NULL; BROADCAST plot.private.unlocked; }; LockPlot: PUBLIC ENTRY PROC [plot: Plot] ~{ ENABLE UNWIND => NULL; IF plot=NIL THEN RETURN; IF plot.private=NIL THEN RETURN; WHILE plot.private.locked DO WAIT plot.private.unlocked; ENDLOOP; IF plot.private=NIL THEN RETURN; -- If somebody destroyed the plot meanwhile plot.private.locked _ TRUE; }; UnlockPlot: PUBLIC ENTRY PROC [plot: Plot]~{ ENABLE UNWIND => NULL; IF plot=NIL THEN RETURN; IF plot.private=NIL THEN RETURN; plot.private.locked _ FALSE; BROADCAST plot.private.unlocked; }; WritePtV: PROC [x, y: REAL, data: REF ANY _ NIL, rope: ROPE _ NIL] RETURNS [quit: BOOL _ FALSE] ~ { <> <> <> x0, y0: REAL; n: INT; r: ROPE; ptData: DrawPtData ~ NARROW[data]; n _ Real.Fix[y]; IF (Real.Fix[ptData.prevPt.y] = n) AND rope=NIL THEN RETURN; x0 _ (x+ptData.or.x)*ptData.mult.x+ptData.plotOr.x; IF x0ptData.window.x+ptData.window.w THEN RETURN; y0 _ ptData.plotOr.y; Draw2d.Line[ptData.context, [x0, y0], [x0, y0+tinyTick]]; r _ IF rope~=NIL THEN rope ELSE Convert.RopeFromInt[n, 16, FALSE]; ShowRopeV[ptData.context, r, [x0 - 2.0, y0+spaceOverTick]]; ptData.prevPt _ [x0, y]; }; WritePtH: PROC [x, y: REAL, data: REF ANY _ NIL, rope: ROPE _ NIL] RETURNS [quit: BOOL _ FALSE] ~ { <> <> x0, y0: REAL; n: INT; r: ROPE; ptData: DrawPtData ~ NARROW[data]; n _ Real.Fix[y]; IF (Real.Fix[ptData.prevPt.y] = n) AND rope=NIL THEN RETURN; x0 _ (x+ptData.or.x)*ptData.mult.x+ptData.plotOr.x; IF x0ptData.window.x+ptData.window.w THEN RETURN; y0 _ ptData.plotOr.y; Draw2d.Line[ptData.context, [x0, y0], [x0, y0+tinyTick]]; Imager.SetXY[ptData.context, [x0 - 2.0, y0+spaceOverTick]]; r _ IF rope~=NIL THEN rope ELSE Convert.RopeFromInt[n, 16, FALSE]; Imager.ShowRope[ptData.context, r]; ptData.prevPt _ [x0, y]; }; DrawPt: PROC [x, y: REAL, data: REF ANY _ NIL, rope: ROPE _ NIL] RETURNS [quit: BOOL _ FALSE] ~ { <> pt: VEC; visible: BOOLEAN; ptData: DrawPtData ~ NARROW[data]; IF ptData.firstPoint THEN { ptData.prevPt _ [(x+ptData.or.x)*ptData.mult.x+ptData.plotOr.x, (y+ptData.or.y)*ptData.mult.y+ptData.plotOr.y]; ptData.firstPoint _ FALSE; ptData.visible _ IsPtInArea[ptData.prevPt, ptData.window]; } ELSE { pt _ [(x+ptData.or.x)*ptData.mult.x+ptData.plotOr.x, (y+ptData.or.y)*ptData.mult.y+ptData.plotOr.y]; visible _ IsPtInArea[pt, ptData.window]; SELECT TRUE FROM visible AND ptData.visible => Draw2d.Line[ptData.context, ptData.prevPt, pt]; visible AND ~ptData.visible => Draw2d.Line[ptData.context, ClipVect[pt, ptData.prevPt, ptData.window], pt]; ~visible AND ptData.visible => Draw2d.Line[ptData.context, ptData.prevPt, ClipVect[ptData.prevPt, pt, ptData.window]]; ~visible AND ~ptData.visible => { pt1, pt2: VEC; IF pt.y~=ptData.prevPt.y THEN { pt1 _ ClipVect[ptData.prevPt, pt, ptData.window]; pt2 _ ClipVect[pt, ptData.prevPt, ptData.window]; IF pt1.x~=pt2.x OR pt1.y~=pt2.y THEN Draw2d.Line[ptData.context, pt1, pt2]; } }; ENDCASE; ptData.prevPt _ pt; ptData.visible _ visible; } }; RefreshPlot: PUBLIC PROC [plot: Plot, axis: AxisList _ NIL, graphs: GraphList _ NIL, within: Rectangle _ WorldRectangle, eraseFirst: BOOL _ FALSE] ~ { IF plot.private=NIL THEN CreatePlotViewer[plot]; IF plot.private.viewer.iconic THEN RETURN; IF NARROW[plot.private.viewer.data, ViewerData].frozen THEN RETURN; RefreshScreen[plot, axis, graphs, within, eraseFirst]; }; RefreshScreen: PROC [plot: Plot, axis: AxisList _ NIL, graphs: GraphList _ NIL, within: Rectangle _ WorldRectangle, eraseFirst: BOOL _ FALSE] ~ { DoRefreshScreen: PROC [viewer: Viewer, context: Imager.Context] ~ { axisFound, graphFound, gridOK: BOOL; wwhite, rred, ggreen, bblue, ppuce: Imager.Color; axisChoice: BOOLEAN = ~(axis=NIL); --test only once the presence of an axis specification graphsChoice: BOOLEAN = ~(graphs=NIL); -- the same for graphs viewerData: ViewerData ~ NARROW[viewer.data]; xoffset, inter: REAL _ 0.0; hAxis: ARRAY DrawingStyle OF REAL _ ALL[0.0]; colorList: LIST OF Color; selectedAxis: Axis _ GetSelectedAxis[plot]; ptData: DrawPtData _ NEW[DrawPtDataRec _ [ window: WorldRectangle, plotOr: [xSpace, ySpace], or: [0.0, 0.0], prevPt: [0.0, 0.0], mult: [1.0, 1.0], context: context, firstPoint: TRUE ]]; <> IF viewer.column= color THEN { wwhite _ grey; rred _ red; ggreen _ green; bblue _ blue; ppuce _ puce; } ELSE { wwhite _ white; rred _ black; ggreen _ black; bblue _ black; ppuce _ black; }; Imager.SetFont[context, currentFont]; IF eraseFirst THEN { Imager.SetColor[context, wwhite]; Imager.MaskRectangle[context, ImagerBackdoor.GetBounds[context]]; -- fill screen <> Imager.SetColor[context, rred]; IF ~viewerData.magOn THEN DrawMag[viewer, context]; <> FOR iTextList: LIST OF PlotText _ plot.texts, iTextList.rest UNTIL iTextList=NIL DO IF iTextList.first.wrt=NIL THEN { RotateAndShow: PROC ~ { <> Imager.SetColor[context, bblue]; Imager.SetXY[context, [ptData.plotOr.x+iTextList.first.bounds.x*viewer.cw, ptData.plotOr.y+iTextList.first.bounds.y*viewer.ch]]; Imager.Move[context]; Imager.RotateT[context, iTextList.first.rotation]; Imager.SetXY[context, [x, y]]; Imager.ShowRope[context, iTextList.first.contents]; }; x, y: REAL; <> x _ SELECT iTextList.first.justifyX FROM left => ptData.plotOr.x+iTextList.first.bounds.x*viewer.cw, center => ptData.plotOr.x+(iTextList.first.bounds.x+MAX[0.0, (iTextList.first.bounds.w-ImagerFont.RopeWidth[currentFont, iTextList.first.contents].x)*0.5])*viewer.cw, right => ptData.plotOr.x+(iTextList.first.bounds.x+MAX[0.0, iTextList.first.bounds.w-ImagerFont.RopeWidth[currentFont, iTextList.first.contents].x])*viewer.cw, ENDCASE => 0.0; <> y _ SELECT iTextList.first.justifyY FROM bottom => ptData.plotOr.y+iTextList.first.bounds.y*viewer.ch, center => ptData.plotOr.y+(iTextList.first.bounds.y+ MAX[0.0, (iTextList.first.bounds.h-ImagerFont.RopeWidth[currentFont, iTextList.first.contents].y)*0.5])*viewer.ch, top => ptData.plotOr.y+(iTextList.first.bounds.y+MAX[0.0, iTextList.first.bounds.h-ImagerFont.RopeWidth[currentFont, iTextList.first.contents].y])*viewer.ch, ENDCASE => 0.0; <> Imager.DoSaveAll[context, RotateAndShow]; }; ENDLOOP; }; <> IF plot.axis=NIL THEN RETURN; <> gridOK _ viewerData.grid; hAxis _ SetHeights[plot]; <> IF gridOK AND eraseFirst THEN { x, y: REAL; unit: REAL; <> unit _ Normalize[plot.axis.first.bounds.w/20.0]; <> FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO iAxisList.first.bounds.w _ 20.0*unit; ENDLOOP; <> Imager.SetColor[context, ggreen]; x _ ptData.plotOr.x; y _ ptData.plotOr.y+viewer.ch/2.0; Draw2d.Line[context, [x, y], [x+viewer.cw, y]]; y _ y-5.0; <> FOR i: INT IN [1..19] DO x _ ptData.plotOr.x+i*viewer.cw/20.0; Draw2d.Line[context, [x, y], [x, y+10.0]]; ENDLOOP; <> ShowRope[ptData.plotOr.x+viewer.cw/20.0, y+15.0, IO.PutFR["%g", IO.real[unit]], context, bblue] }; <> FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO <> IF axisChoice THEN { axisFound _ FALSE; FOR jAxisList: AxisList _ axis, jAxisList.rest UNTIL jAxisList=NIL DO IF jAxisList.first=iAxisList.first THEN { axisFound _ TRUE; EXIT; }; ENDLOOP; } ELSE axisFound _ TRUE; <> IF axisFound THEN { <> xoffset _ 2.0; colorList _ graphColorList; <> inter _ IF iAxisList.first.style=hexaV THEN hAxis[hexaV]*(iAxisList.first.maxChars+1.0) ELSE hAxis[iAxisList.first.style]; <> ptData.or.x _ -iAxisList.first.bounds.x; ptData.or.y _ -iAxisList.first.bounds.y; ptData.mult.x _ viewer.cw/iAxisList.first.bounds.w; ptData.mult.y _ (inter-charHeight)/iAxisList.first.bounds.h; ptData.window _ [ptData.plotOr.x, ptData.plotOr.y, viewer.cw, inter]; IF eraseFirst THEN { <> IF iAxisList.first.axisData[X].visible THEN { Imager.SetColor[context, ggreen]; Draw2d.Line[context, ptData.plotOr, [ptData.plotOr.x+viewer.cw, ptData.plotOr.y]]; }; IF iAxisList.first.axisData[Y].visible THEN { Imager.SetColor[context, ggreen]; Draw2d.Line[context, ptData.plotOr, [ptData.plotOr.x, ptData.plotOr.y+inter]]; }; <> IF iAxisList.first=selectedAxis THEN ShowRopeInv[ptData.plotOr.x+xAxisName, ptData.plotOr.y+yAxisName, iAxisList.first.name, context, wwhite, bblue] ELSE ShowRopeInv[ptData.plotOr.x+xAxisName, ptData.plotOr.y+yAxisName, iAxisList.first.name, context, bblue, wwhite]; }; <> FOR iGraphList: GraphList _ iAxisList.first.graphs, iGraphList.rest UNTIL iGraphList=NIL DO <> IF graphsChoice THEN { graphFound _ FALSE; FOR jGraphList: GraphList _ graphs, jGraphList.rest UNTIL jGraphList=NIL DO IF jGraphList.first=iGraphList.first THEN { graphFound _ TRUE; EXIT; }; ENDLOOP; IF ~graphFound THEN LOOP; }; <> ptData.firstPoint _ TRUE; Imager.SetColor[context, colorList.first]; SELECT iAxisList.first.style FROM analog => [] _ iGraphList.first.class.enumerate[plot, iGraphList.first, within, DrawPt, ptData]; hexaH => [] _ iGraphList.first.class.enumerate[plot, iGraphList.first, within, WritePtH, ptData]; hexaV => [] _ iGraphList.first.class.enumerate[plot, iGraphList.first, within, WritePtV, ptData]; ENDCASE; <> IF eraseFirst THEN ShowRope[ptData.plotOr.x+xoffset, ptData.plotOr.y+inter*0.5, iGraphList.first.name, context, colorList.first]; <> xoffset _ xoffset+ImagerFont.RopeWidth[currentFont, iGraphList.first.name].x+5.0; IF colorList.rest#NIL THEN colorList _ colorList.rest ELSE colorList _ graphColorList; ENDLOOP; }; <> ptData.plotOr.y _ ptData.plotOr.y+inter; ENDLOOP; }; IF plot#NARROW[plot.private.viewer.data, ViewerData].plot THEN ERROR; <> DrawInViewer[plot.private.viewer, DoRefreshScreen, FALSE]; }; ProduceIPMaster: PUBLIC PROC [plot: Plot] ~ { <> DoPrint: PROC [context: Imager.Context] ~ { <> xoffset, inter: REAL; nAxis, hAxis, cAxis: ARRAY DrawingStyle OF REAL _ ALL[0.0]; colorList: LIST OF Color; ptData: DrawPtData _ NEW[DrawPtDataRec _ [ window: WorldRectangle, plotOr: [50.0, 100.0], or: [0.0, 0.0], prevPt: [0.0, 0.0], mult: [1.0, 1.0], context: context, firstPoint: TRUE ]]; <> Imager.SetStrokeEnd[context, round]; Imager.SetStrokeJoint[context, round]; Imager.SetFont[context, pressFont]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO nAxis[iAxisList.first.style] _ nAxis[iAxisList.first.style] + 1.0; cAxis[iAxisList.first.style] _ cAxis[iAxisList.first.style] + iAxisList.first.maxChars; ENDLOOP; inter _ pageSize.y/(nAxis[analog]+nAxis[hexaH]+cAxis[hexaV]); hAxis[hexaH] _ MIN[inter, charHeight+10.0]; hAxis[hexaV] _ MIN[inter, charHeight*1.15]; hAxis[analog] _ (pageSize.y -hAxis[hexaH]*nAxis[hexaH] -hAxis[hexaV]*cAxis[hexaV]) /nAxis[analog]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO xoffset _ 0.0; colorList _ graphColorList; inter _ IF iAxisList.first.style=hexaV THEN hAxis[hexaV]*iAxisList.first.maxChars ELSE hAxis[iAxisList.first.style]; ptData.or.x _ -iAxisList.first.bounds.x; ptData.or.y _ -iAxisList.first.bounds.y; ptData.mult.x _ pageSize.x/iAxisList.first.bounds.w; ptData.mult.y _ (inter-10.0)/iAxisList.first.bounds.h; ptData.window _ [ptData.plotOr.x, ptData.plotOr.y, pageSize.x, inter]; IF iAxisList.first.axisData[X].visible THEN { Imager.SetStrokeWidth[context, fineStroke]; Imager.SetColor[context, green]; Imager.MaskVector[context, ptData.plotOr, [ptData.plotOr.x+1000.0, ptData.plotOr.y]]; }; IF iAxisList.first.axisData[Y].visible THEN { Imager.SetStrokeWidth[context, fineStroke]; Imager.SetColor[context, green]; Imager.MaskVector[context, ptData.plotOr, [ptData.plotOr.x, ptData.plotOr.y+inter]]; }; ShowRope[ptData.plotOr.x, ptData.plotOr.y+inter*0.1, iAxisList.first.name, context, blue]; FOR iGraphList: GraphList _ iAxisList.first.graphs, iGraphList.rest UNTIL iGraphList=NIL DO ptData.firstPoint _ TRUE; Imager.SetStrokeWidth[context, coarseStroke]; Imager.SetColor[context, colorList.first]; SELECT iAxisList.first.style FROM analog => [] _ iGraphList.first.class.enumerate[plot, iGraphList.first, within, DrawPt, ptData]; hexaH => [] _ iGraphList.first.class.enumerate[plot, iGraphList.first, within, WritePtH, ptData]; hexaV => [] _ iGraphList.first.class.enumerate[plot, iGraphList.first, within, WritePtV, ptData]; ENDCASE; ShowRope[ptData.plotOr.x+xoffset, ptData.plotOr.y+inter*0.5, iGraphList.first.name, context, colorList.first]; xoffset _ xoffset+ImagerFont.RopeWidth[currentFont, iGraphList.first.name].x+5.0; IF colorList.rest#NIL THEN colorList _ colorList.rest ELSE colorList _ graphColorList; ENDLOOP; ptData.plotOr.y _ ptData.plotOr.y+inter; ENDLOOP; }; fileName: Rope.ROPE _ Rope.Cat["///Temp/PlotGraph/", plot.name^, ".interpress"]; within: Rectangle _ [plot.lowerBounds.x, plot.lowerBounds.y, plot.upperBounds.x-plot.lowerBounds.x, plot.upperBounds.y - plot.lowerBounds.y]; ip: ImagerInterpress.Ref _ ImagerInterpress.Create[fileName]; rgbLinear: Imager.ColorOperator ~ ImagerColorOperator.RGBLinearColorModel[255]; ImagerInterpress.DeclareColorOperator[ip, rgbLinear]; ImagerInterpress.DeclareFont[ip, pressFont]; ImagerInterpress.DoPage[ip, DoPrint, pressScale]; ImagerInterpress.Close[ip]; MessageWindow.Append[Rope.Cat[fileName, " created"],TRUE]; }; DeletePlot: PUBLIC PROC [plot: Plot] ~ { <> viewer: Viewer _ plot.private.viewer; ViewerOps.DestroyViewer[viewer]; }; <<>> <> SetDefaults: PROC [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] ~ { viewer: Viewer ~ NARROW[parent]; viewerData: ViewerData ~ NARROW[viewer.data]; plot: Plot _ viewerData.plot; IF viewerData.magOn THEN MagOnOff[viewer, true, yellow, FALSE, FALSE]; LockPlot[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO iAxisList.first.bounds.x _ plot.lowerBounds.x; iAxisList.first.bounds.y _ plot.lowerBounds.y; iAxisList.first.bounds.w _ plot.upperBounds.x - plot.lowerBounds.x; iAxisList.first.bounds.h _ plot.upperBounds.y - plot.lowerBounds.y; ENDLOOP; UnlockPlot[plot]; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE]; }; GridOnOff: PROC [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] ~ { viewer: Viewer ~ NARROW[parent]; viewerData: ViewerData ~ NARROW[viewer.data]; viewerData.grid _ ~viewerData.grid; RefreshScreen[plot: viewerData.plot, within: WorldRectangle, eraseFirst: TRUE] }; IPBut: PROC [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] ~ { viewer: Viewer ~ NARROW[parent]; viewerData: ViewerData ~ NARROW[viewer.data]; ProduceIPMaster[viewerData.plot]; }; Freeze: PROC [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] ~ { viewer: Viewer ~ NARROW[parent]; viewerData: ViewerData ~ NARROW[viewer.data]; liasonState: BOOLEAN _ NARROW[clientData, REF BOOLEAN]^; Menus.ReplaceMenuEntry[viewer.menu, liasonEntry[liasonState], liasonEntry[~liasonState]]; viewerData.frozen _ ~viewerData.frozen; ViewerOps.PaintViewer[viewer, menu]; }; MagScaleX: PROC [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] ~ { viewer: Viewer ~ NARROW[parent]; viewerData: ViewerData ~ NARROW[viewer.data]; plot: Plot ~ viewerData.plot; alpha: REAL; IF mouseButton=yellow THEN RETURN; alpha _ IF mouseButton=red THEN 0.5 ELSE 2.0; IF shift THEN alpha _ alpha*alpha; IF viewerData.xScale*alpha>1.0 THEN RETURN; IF viewerData.magOn THEN { viewerData.xScale _ viewerData.xScale*alpha; PlotScaleX[plot, alpha]; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] } ELSE { MagExpand: PROC [viewer: Viewer, context: Imager.Context] ~ { Imager.SetColor[context, IF viewer.column=color THEN grey ELSE white]; DrawMag[viewer, context]; viewerData.xScale _ viewerData.xScale*alpha; Imager.SetColor[context, IF viewer.column=color THEN red ELSE black]; DrawMag[viewer, context]; }; DrawInViewer[viewer, MagExpand, FALSE]; }; }; ScaleX: PROCEDURE [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] ~ { viewer: Viewer ~ NARROW[parent]; viewerData: ViewerData ~ NARROW[viewer.data]; plot: Plot ~ viewerData.plot; alpha: REAL _ 2.0; IF mouseButton=yellow THEN RETURN; IF mouseButton=red THEN alpha _ 0.5; IF shift THEN alpha _ alpha*alpha; viewerData.xScale _ MIN[1.0, viewerData.xScale/alpha]; IF ~viewerData.magOn THEN { PlotScaleX[plot, alpha]; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; }; ScaleY: PROCEDURE [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] ~ { viewer: Viewer ~ NARROW[parent]; viewerData: ViewerData ~ NARROW[viewer.data]; plot: Plot ~ viewerData.plot; alpha: REAL _ 2.0; IF mouseButton=yellow THEN RETURN; IF mouseButton=red THEN alpha _ 0.5; IF shift THEN alpha _ alpha*alpha; LockPlot[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO iAxisList.first.bounds.h _ alpha*iAxisList.first.bounds.h; ENDLOOP; UnlockPlot[plot]; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; MagOnOff: PROCEDURE [parent: REF ANY, clientData: REF ANY, mouseButton: Menus.MouseButton, shift, control: BOOL] ~ { viewer: Viewer ~ NARROW[parent]; viewerData: ViewerData ~ NARROW[viewer.data]; plot: Plot ~ viewerData.plot; magState: BOOLEAN _ NARROW[clientData, REF BOOLEAN]^; IF magState#viewerData.magOn THEN ERROR; -- ????? Menus.ReplaceMenuEntry[viewer.menu, magEntry[magState], magEntry[~magState]]; ViewerOps.PaintViewer[viewer, menu]; IF viewerData.magOn THEN { LockPlot[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO iAxisList.first.bounds.w _ iAxisList.first.bounds.w/viewerData.xScale; iAxisList.first.bounds.x _ iAxisList.first.bounds.x-iAxisList.first.bounds.w*viewerData.xOr; ENDLOOP; UnlockPlot[plot]; } ELSE { LockPlot[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO iAxisList.first.bounds.x _ iAxisList.first.bounds.x+iAxisList.first.bounds.w*viewerData.xOr; iAxisList.first.bounds.w _ viewerData.xScale*iAxisList.first.bounds.w; ENDLOOP; UnlockPlot[plot]; }; viewerData.magOn _ ~viewerData.magOn; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE]; }; <> PaintProc: ViewerClasses.PaintProc ~ { -- repaint screen for updates <> SELECT whatChanged FROM NIL => { -- window resized, redraw viewerData: ViewerData ~ NARROW[self.data]; RefreshScreen[plot: viewerData.plot, within: WorldRectangle, eraseFirst: TRUE] }; ENDCASE => { -- call path for DrawInViewer NARROW[whatChanged, REF PROC[Viewer, Imager.Context]]^[self, context]; }; }; NotifyProc: ViewerClasses.NotifyProc ~ { <> x, y, t, v: REAL; viewerData: ViewerData ~ NARROW[self.data]; plot: Plot ~ viewerData.plot; IF InputFocus.GetInputFocus[].owner#self THEN InputFocus.SetInputFocus[self, plot]; IF ISTYPE[input.first, TIPUser.TIPScreenCoords] -- If input is coords from mouse THEN { mousePos: TIPUser.TIPScreenCoords _ NARROW[input.first]; x _ mousePos.mouseX; y _ mousePos.mouseY; IF ISTYPE[input.rest.first, ATOM] THEN { actionName: ATOM _ NARROW[input.rest.first]; thisAxis: Axis; [thisAxis, t, v] _ GetAxis[self, x, y]; SELECT actionName FROM $Refresh => { RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; $WriteCoord => { IF thisAxis.style=analog THEN DrawRope[[x, y], IO.PutFR["t:%g,v:%g", IO.real[t], IO.real[v]], self, IF self.column= color THEN red ELSE black] ELSE DrawRope[[x, y], IO.PutFR["t:%d", IO.real[t]], self, IF self.column= color THEN red ELSE black]; RETURN; }; $MoveMag => { MoveMag: PROC [viewer: Viewer, context: Imager.Context] ~ { Imager.SetColor[context, IF viewer.column=color THEN grey ELSE white]; DrawMag[viewer, context]; viewerData.xOr _ x/viewer.cw; Imager.SetColor[context, IF viewer.column=color THEN red ELSE black]; DrawMag[viewer, context]; }; IF ~viewerData.magOn THEN DrawInViewer[self, MoveMag, FALSE]; <> }; $SelectAxis => { SelectAxis[plot, thisAxis]; }; $MoveAxis => { selectedAxis: Axis _ GetSelectedAxis[plot]; [] _ MoveAxis[plot, selectedAxis, thisAxis]; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; $CopyAxis => { selectedAxis: Axis _ GetSelectedAxis[plot]; [] _ InsertAxis[plot, CopyAxis[thisAxis], selectedAxis]; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; $RevMoveAxis => { selectedAxis: Axis _ GetSelectedAxis[plot]; [] _ MoveAxis[plot, thisAxis, selectedAxis]; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; $DelClickedAxis => { [] _ DeleteAxis[plot, thisAxis]; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; $XChange => { selectedAxis: Axis _ GetSelectedAxis[plot]; [] _ XChangeAxis[plot, thisAxis, selectedAxis]; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; $DelSelection => { DeleteSelection[plot]; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; ENDCASE => { IF plot.eventProc#NIL THEN plot.eventProc[plot, thisAxis, [t, v], actionName]; }; <<>> }; }; }; ModifyProc: ViewerClasses.ModifyProc ~ { <<= PROC [self: Viewer, change: ModifyAction], ModifyAction: TYPE = {set, push, pop, kill}>> viewerData: ViewerData ~ NARROW[self.data]; plot: Plot ~ viewerData.plot; SELECT change FROM set => NULL; push => NULL; pop => NULL; kill => SelectAxis[plot, NIL]; ENDCASE; }; DestroyProc: ViewerClasses.DestroyProc ~ { <<~ PROC [self: Viewer] This will be called when the viewer is destroyed>> viewerData: ViewerData ~ NARROW[self.data]; plot: Plot _ viewerData.plot; LockPlot[plot]; plot.axis _ NIL; AwakeOthers[plot]; plot.private _ NIL; }; VScrollProc: ViewerClasses.ScrollProc ~ { <> <> <> viewerData: ViewerData ~ NARROW[self.data]; plot: Plot _ viewerData.plot; SELECT op FROM up => { LockPlot[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO iAxisList.first.bounds.y _ iAxisList.first.bounds.y - amount*iAxisList.first.bounds.h/self.ch; ENDLOOP; UnlockPlot[plot]; }; down => { LockPlot[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO iAxisList.first.bounds.y _ iAxisList.first.bounds.y + amount*iAxisList.first.bounds.h/self.ch; ENDLOOP; UnlockPlot[plot]; }; thumb => { RETURN; <> <> <> }; query => { top _ 0; bottom _ 100; IF plot.upperBounds.y=plot.lowerBounds.y THEN RETURN; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO top _ MAX[top, Real.FixI[100.0*(plot.upperBounds.y-iAxisList.first.bounds.y-iAxisList.first.bounds.h) /(plot.upperBounds.y-plot.lowerBounds.y)]]; bottom _ MIN[bottom, Real.FixI[100.0*(plot.upperBounds.y-iAxisList.first.bounds.y) /(plot.upperBounds.y-plot.lowerBounds.y)]]; ENDLOOP; RETURN; }; ENDCASE; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; HScrollProc: ViewerClasses.HScrollProc ~ { <> <> <> viewerData: ViewerData ~ NARROW[self.data]; plot: Plot _ viewerData.plot; SELECT op FROM left => { LockPlot[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO iAxisList.first.bounds.x _ iAxisList.first.bounds.x + amount*iAxisList.first.bounds.w/self.cw; ENDLOOP; UnlockPlot[plot]; }; right => { LockPlot[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO iAxisList.first.bounds.x _ iAxisList.first.bounds.x - amount*iAxisList.first.bounds.w/self.cw; ENDLOOP; UnlockPlot[plot]; }; thumb => { RETURN; <> <> <> }; query => { left _ 0; right _ 100; IF plot.upperBounds.x=plot.lowerBounds.x THEN RETURN; <> <> <> <> FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO left _ MAX[left, Real.FixI[100.0*(iAxisList.first.bounds.x-plot.lowerBounds.x) /(plot.upperBounds.x-plot.lowerBounds.x)]]; right _ MIN[right, Real.FixI[100.0*(iAxisList.first.bounds.x+iAxisList.first.bounds.w-plot.lowerBounds.x) /(plot.upperBounds.x-plot.lowerBounds.x)]]; ENDLOOP; RETURN; }; ENDCASE; RefreshScreen[plot: plot, within: WorldRectangle, eraseFirst: TRUE] }; AdjustProc: ViewerClasses.AdjustProc ~ { <<= PROC [self: Viewer] RETURNS [adjusted: BOOL _ FALSE]>> <> adjusted _ TRUE; }; <> <<>> DeleteSelection : PUBLIC PROC [plot: Plot] ~ { axisList: AxisList _ plot.axis; IF plot.selection=NIL THEN RETURN; UNTIL plot.selection=NIL DO WITH plot.selection.first SELECT FROM axis: Axis => DeleteAxis[plot, axis]; graph: Graph => NULL; point: GraphPoint => NULL; text: PlotText => NULL; ENDCASE => NULL; plot.selection _ plot.selection.rest; ENDLOOP; }; InsertAxis: PUBLIC PROC [plot: Plot, axis, after: Axis] ~ { axisList: AxisList _ plot.axis; IF axis=NIL THEN RETURN; LockPlot[plot]; IF after=NIL THEN plot.axis _ CONS[axis, plot.axis] ELSE { UNTIL axisList.first=after OR axisList=NIL DO axisList _ axisList.rest ENDLOOP; IF axisList=NIL THEN {UnlockPlot[plot]; RETURN}; axisList.rest _ CONS[axis, axisList.rest]; }; UnlockPlot[plot]; }; DeleteAxis: PUBLIC PROC [plot: Plot, axis: Axis] ~ { axisList: AxisList _ plot.axis; IF axisList=NIL THEN RETURN; LockPlot[plot]; IF axisList.first=axis THEN {plot.axis _ plot.axis.rest; UnlockPlot[plot]; RETURN}; UNTIL axisList.rest.first=axis DO axisList _ axisList.rest; IF axisList.rest=NIL THEN {UnlockPlot[plot]; RETURN}; ENDLOOP; axisList.rest _ axisList.rest.rest; UnlockPlot[plot]; }; MoveAxis: PUBLIC PROC [plot: Plot, axis, after: Axis] ~ { DeleteAxis[plot, axis]; InsertAxis[plot, axis, after]; }; XChangeAxis: PUBLIC PROC [plot: Plot, axis1, axis2: Axis] ~ { axisList: AxisList _ plot.axis; IF axisList=NIL THEN RETURN; LockPlot[plot]; UNTIL axisList=NIL DO SELECT axisList.first FROM axis1 => axisList.first _ axis2; axis2 => axisList.first _ axis1; ENDCASE; axisList _ axisList.rest; ENDLOOP; UnlockPlot[plot]; }; CopyAxis: PUBLIC PROC [axis: Axis] RETURNS [duplicate: Axis] ~ { duplicate _ NEW[AxisRec _ [ graphs: axis.graphs, bounds: axis.bounds, name: axis.name, style: axis.style, maxChars: axis.maxChars, axisData: axis.axisData ]]; }; <> <<>> DrawInViewer: PROC [viewer: Viewer, proc: PROC [Viewer, Imager.Context], clear: BOOL _ FALSE] ~ { <> drawProc: REF PROC[Viewer, Imager.Context] _ NIL; TRUSTED { drawProc _ NEW[PROC[Viewer, Imager.Context] _ proc]; }; ViewerOps.PaintViewer[ viewer: viewer,-- pass record to viewer painter hint: client, whatChanged: drawProc, clearClient: clear ]; }; SetHeights: PROC [plot: Plot] RETURNS [hAxis: ARRAY DrawingStyle OF REAL _ ALL[0.0]] ~ { viewer: Viewer ~ plot.private.viewer; nAxis, cAxis: ARRAY DrawingStyle OF REAL _ ALL[0.0]; inter: REAL; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO <> nAxis[iAxisList.first.style] _ nAxis[iAxisList.first.style] + 1.0; cAxis[iAxisList.first.style] _ cAxis[iAxisList.first.style] + iAxisList.first.maxChars+1.0; ENDLOOP; <> inter _ (viewer.ch-2*ySpace) /(nAxis[analog]+nAxis[hexaH]+cAxis[hexaV]); hAxis[hexaH] _ MIN[inter, charHeight+10.0]; hAxis[hexaV] _ MIN[inter, charHeight]; IF nAxis[analog]#0 THEN hAxis[analog] _ (viewer.ch-2*ySpace-hAxis[hexaH]*nAxis[hexaH] -hAxis[hexaV]*cAxis[hexaV]) /nAxis[analog]; }; PlotScaleX: PROC [plot: Plot, alpha: REAL] ~ { LockPlot[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO iAxisList.first.bounds.w _ alpha*iAxisList.first.bounds.w; ENDLOOP; UnlockPlot[plot]; }; DrawMag: PROC [viewer: Viewer, context: Imager.Context] ~ { viewerData: ViewerData ~ NARROW[viewer.data]; x: REAL _ viewer.cw*viewerData.xOr; Draw2d.Line[context, [x, 0.0], [x, viewer.ch]]; x _ x+viewer.cw*viewerData.xScale; Draw2d.Line[context, [x, 0.0], [x, viewer.ch]]; }; ClipVect: PROC [fix, mov: VEC, area: Rectangle] RETURNS [newPt: VEC] ~ { <> slope: REAL; newPt _ mov; IF fix.x~=mov.x THEN { slope _ (fix.y-mov.y)/(fix.x-mov.x); IF newPt.xarea.x+area.w THEN {newPt.x _ area.x+area.w; newPt.y _ slope*(newPt.x-fix.x) + fix.y}; }; IF fix.y~=mov.y THEN { slope _ (fix.x-mov.x)/(fix.y-mov.y); IF newPt.yarea.y+area.h THEN {newPt.y _ area.y+area.h; newPt.x _ (newPt.y-fix.y)*slope + fix.x}; }; }; IsPtInArea: PROC [pt: VEC, area: Rectangle] RETURNS [inside: BOOLEAN _ FALSE] ~ { IF pt.xarea.x+area.w THEN RETURN; IF pt.y>area.y+area.h THEN RETURN; inside _ TRUE; }; ShowRopeInv: PROC [x, y: REAL, rope: Rope.ROPE, context: Imager.Context, color, background: Imager.Color] ~ { Imager.SetColor[context, background]; Imager.MaskRectangle[context, [x, y-1.0, ImagerFont.RopeWidth[currentFont, rope].x, charHeight+2.0]]; Imager.SetXY[context, [x, y]]; Imager.SetColor[context, color]; Imager.ShowRope[context, rope]; }; ShowRopeV: PROC[context: Imager.Context, rope: Rope.ROPE, pos: VEC] ~ { IF rope=NIL THEN RETURN; FOR i: INT _ Rope.Length[rope]-1, i-1 UNTIL i=-1 DO Imager.SetXY[context, pos]; Imager.ShowChar[context, Rope.InlineFetch[rope, i]]; pos.y _ pos.y+ charHeight; ENDLOOP; }; ShowRope: PROC[x, y: REAL, rope: Rope.ROPE, context: Imager.Context, color: Imager.Color] ~ { IF rope=NIL THEN RETURN; Imager.SetColor[context, color]; Imager.SetXY[context, [x, y]]; Imager.ShowRope[context, rope]; }; DrawRopeV: PUBLIC PROC[pos: VEC, rope: Rope.ROPE, viewer: Viewer, color: Imager.Color] ~ { DoDrawRope: PROC [viewer: Viewer, context: Imager.Context] ~ { Imager.SetColor[context, color]; ShowRopeV[context, rope, pos]; }; DrawInViewer[viewer, DoDrawRope, FALSE];-- ask the viewer procs to call you back }; DrawRope: PUBLIC PROC[pos: VEC, rope: Rope.ROPE, viewer: Viewer, color: Imager.Color] ~ { DoDrawRope: PROC [viewer: Viewer, context: Imager.Context] ~ { Imager.SetFont[context, currentFont]; ShowRope[pos.x, pos.y, rope, context, color]; }; DrawInViewer[viewer, DoDrawRope, FALSE];-- ask the viewer procs to call you back }; DrawRopeInv: PUBLIC PROC[pos: VEC, rope: Rope.ROPE, viewer: Viewer, color, background: Imager.Color] ~ { DoDrawRope: PROC [viewer: Viewer, context: Imager.Context] ~ { Imager.SetFont[context, currentFont]; ShowRopeInv[pos.x, pos.y, rope, context, color, background]; }; DrawInViewer[viewer, DoDrawRope, FALSE];-- ask the viewer procs to call you back }; Normalize: PROC [r: REAL] RETURNS [dec: REAL] ~ { <> neg: BOOL _ r<0.0; unsigned: REAL _ IF neg THEN -r ELSE r; base: REAL _ IF unsigned<1.0 THEN 10.0 ELSE 0.1; dec _ 1.0; IF r#0.0 THEN UNTIL unsigned>=1.0 AND unsigned<10.0 DO dec _ dec/base; unsigned _ unsigned*base; ENDLOOP; dec _ SELECT TRUE FROM unsigned<1.5 => dec, unsigned<3.5 => 2.0*dec, unsigned<7.5 => 5.0*dec, ENDCASE => 10.0*dec; IF neg THEN dec _ -dec; }; GetSelectedAxis: PUBLIC PROC[plot: Plot] RETURNS [axis: Axis] ~ { FOR iList: LIST OF REF ANY _ plot.selection, iList.rest UNTIL iList=NIL DO IF ISTYPE[iList.first, Axis] THEN { axis _ NARROW[iList.first]; EXIT; }; ENDLOOP; }; GetSelectedAxisList: PUBLIC PROC[plot: Plot] RETURNS [axisList: LIST OF Axis] ~ { axisList _ NIL; FOR iList: LIST OF REF ANY _ plot.selection, iList.rest UNTIL iList=NIL DO IF ISTYPE[iList.first, Axis] THEN axisList _ CONS[NARROW[iList.first, Axis], axisList]; ENDLOOP; }; SelectAxis: PUBLIC PROC [plot: Plot, axis: Axis] ~ { selectedAxis: Axis _ GetSelectedAxis[plot]; self : Viewer _ plot.private.viewer; xor, yor, inter: REAL; hAxis: ARRAY DrawingStyle OF REAL _ ALL[0.0]; bblue: Imager.Color _ IF self.column=color THEN blue ELSE black; wwhite: Imager.Color _ IF self.column=color THEN grey ELSE white; plot.selection _ LIST[axis]; xor _ xSpace; yor _ ySpace; hAxis _ SetHeights[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO inter _ IF iAxisList.first.style=hexaV THEN hAxis[hexaV]*(iAxisList.first.maxChars+1.0) ELSE hAxis[iAxisList.first.style]; IF iAxisList.first=selectedAxis THEN DrawRopeInv[[xor+xAxisName, yor+yAxisName], iAxisList.first.name, self, bblue, wwhite]; IF iAxisList.first=axis THEN DrawRopeInv[[xor+xAxisName, yor+yAxisName], iAxisList.first.name, self, wwhite, bblue]; yor _ yor+inter; ENDLOOP; }; GetAxis: PROC [self: Viewer, x, y: REAL] RETURNS [axis: Axis, localx, localy: REAL] ~ { viewerData: ViewerData ~ NARROW[self.data]; plot: Plot _ viewerData.plot; xor, yor, inter, t, v: REAL; hAxis: ARRAY DrawingStyle OF REAL _ ALL[0.0]; xor _ xSpace; yor _ ySpace; hAxis _ SetHeights[plot]; FOR iAxisList: AxisList _ plot.axis, iAxisList.rest UNTIL iAxisList=NIL DO inter _ IF iAxisList.first.style=hexaV THEN hAxis[hexaV]*iAxisList.first.maxChars ELSE hAxis[iAxisList.first.style]; IF y>=yor AND y> SelectGraph: PUBLIC PROC [plot: Plot, graph: Graph] ~ { plot.selection _ LIST[graph]; }; AddGraph: PUBLIC PROC [plot: Plot, graph: Graph] ~ { plot.selection _ CONS[graph, plot.selection]; }; GetSelectedGraph: PUBLIC PROC [plot: Plot] RETURNS [graph: Graph] ~ { FOR iList: LIST OF REF ANY _ plot.selection, iList.rest UNTIL iList=NIL DO IF ISTYPE[iList.first, Graph] THEN { graph _ NARROW[iList.first]; EXIT; }; ENDLOOP; }; GetSelectedGraphList: PUBLIC PROC [plot: Plot] RETURNS [graphList: LIST OF Graph] ~ { graphList _ NIL; FOR iList: LIST OF REF ANY _ plot.selection, iList.rest UNTIL iList=NIL DO IF ISTYPE[iList.first, Graph] THEN graphList _ CONS[NARROW[iList.first, Graph], graphList]; ENDLOOP; }; <> SelectPoint: PUBLIC PROC [plot: Plot, point: GraphPoint] ~ { plot.selection _ LIST[point]; }; AddPoint: PUBLIC PROC [plot: Plot, point: GraphPoint] ~ { plot.selection _ CONS[point, plot.selection]; }; GetSelectedPoint: PUBLIC PROC [plot: Plot] RETURNS [point: GraphPoint] ~ { FOR iList: LIST OF REF ANY _ plot.selection, iList.rest UNTIL iList=NIL DO IF ISTYPE[iList.first, GraphPoint] THEN { point _ NARROW[iList.first]; EXIT; }; ENDLOOP; }; GetSelectedPointList: PUBLIC PROC [plot: Plot] RETURNS [pointList: LIST OF GraphPoint] ~ { pointList _ NIL; FOR iList: LIST OF REF ANY _ plot.selection, iList.rest UNTIL iList=NIL DO IF ISTYPE[iList.first, GraphPoint] THEN pointList _ CONS[NARROW[iList.first, GraphPoint], pointList]; ENDLOOP; }; InsertPoint: PUBLIC PROC [graph: Graph, x, y: REAL] RETURNS [ok: BOOL _ TRUE] ~ { ok _ graph.class.insert#NIL; IF ok THEN graph.class.insert[graph, x, y]; }; DeletePoint: PUBLIC PROC [graph: Graph, x, y: REAL] RETURNS [ok: BOOL _ TRUE] ~ { ok _ graph.class.delete#NIL; IF ok THEN graph.class.delete[graph, x, y]; }; <> SelectText: PUBLIC PROC [plot: Plot, text: PlotText] ~ { plot.selection _ LIST[text]; }; AddText: PUBLIC PROC [plot: Plot, text: PlotText] ~ { plot.selection _ CONS[text, plot.selection]; }; GetSelectedText: PUBLIC PROC [plot: Plot] RETURNS [text: PlotText] ~ { FOR iList: LIST OF REF ANY _ plot.selection, iList.rest UNTIL iList=NIL DO IF ISTYPE[iList.first, PlotText] THEN { text _ NARROW[iList.first]; EXIT; }; ENDLOOP; }; GetSelectedTextList: PUBLIC PROC [plot: Plot] RETURNS [textList: LIST OF PlotText] ~ { textList _ NIL; FOR iList: LIST OF REF ANY _ plot.selection, iList.rest UNTIL iList=NIL DO IF ISTYPE[iList.first, PlotText] THEN textList _ CONS[NARROW[iList.first, PlotText], textList]; ENDLOOP; }; MoveText: PUBLIC PROC [plot: Plot, text: PlotText, position: VEC] ~ { text.bounds.x _ position.x; text.bounds.y _ position.y; }; RotateText: PUBLIC PROC [plot: Plot, text: PlotText, alpha: REAL] ~ { text.rotation _ text.rotation+alpha; }; <> <<>> black: PUBLIC Imager.Color _ ImagerColor.ColorFromRGB[ [ R: 0.0, G: 0.0, B: 0.0 ] ]; white: PUBLIC Imager.Color _ ImagerColor.ColorFromRGB[ [ R: 1.0, G: 1.0, B: 1.0 ] ]; grey: PUBLIC Imager.Color _ ImagerDitheredDevice.ColorFromSpecialPixel[[190, null]]; red: PUBLIC Imager.Color _ ImagerColor.ColorFromRGB[ [ R: 1.0, G: 0.0, B: 0.0 ] ]; green: PUBLIC Imager.Color _ ImagerColor.ColorFromRGB[ [ R: 0.0, G: 1.0, B: 0.0 ] ]; blue: PUBLIC Imager.Color _ ImagerColor.ColorFromRGB[ [ R: 0.0, G: 0.0, B: 1.0 ] ]; puce: PUBLIC Imager.Color _ ImagerColor.ColorFromRGB[ [ R: 0.5, G: 0.2, B: 0.4 ] ]; defaultScalex: REAL _ 0.01; currentFont: Imager.Font _ ImagerFont.Find["Xerox/TiogaFonts/Gacha8"]; pressFont: Imager.Font _ ImagerFont.Scale[ImagerFont.Find["Xerox/PressFonts/Helvetica-brr"], 18.0]; pressScale: REAL _ 0.0002; pageSize: VEC _ [1000.0, 1250.0]; fineStroke: REAL _ 1.0; coarseStroke: REAL _ 3.0; charHeight: REAL _ ImagerFont.FontBoundingBox[currentFont].ascent+1.0; tinyTick: REAL _ 3.0; spaceOverTick: REAL _ 4.0; xSpace: REAL _ 2.0; ySpace: REAL _ 12.0; plotGPictureClass: ViewerClasses.ViewerClass _ NEW [ ViewerClasses.ViewerClassRec _ [ notify: NotifyProc, -- procedure to respond to input events (from TIP table) paint: PaintProc, -- procedure called when viewer contents must be repainted modify: ModifyProc, -- reports InputFocus changes destroy: DestroyProc, -- procedure to clean up when done scroll: VScrollProc, -- procedure to respond to vertical scroll bar hits hscroll: HScrollProc, -- procedure to respond to horizontal scroll bar hits adjust: AdjustProc, -- called when viewer size is changed <<-- Tip table (translates mouse events to commands)>> tipTable: TIPUser.InstantiateNewTIPTable["PlotGraph.TIP"], icon: Icons.NewIconFromFile["PlotGraph.icons", 3], cursor: crossHairsCircle -- cursor when mouse is in viewer ] ]; true: REF BOOLEAN _ NEW[BOOLEAN _ TRUE]; false: REF BOOLEAN _ NEW[BOOLEAN _ FALSE]; resetEntry: Menus.MenuEntry _ Menus.CreateEntry[ name: "Reset", proc: SetDefaults, clientData: NIL, documentation: "Reset graphViewer" ]; magOffEntry: Menus.MenuEntry _ Menus.CreateEntry[ name: "MagOff", proc: MagOnOff, clientData: false, documentation: "Magnifier switch" ]; magOnEntry: Menus.MenuEntry _ Menus.CreateEntry[ name: "MagOn", proc: MagOnOff, clientData: true, documentation: "Magnifier switch" ]; gratEntry: Menus.MenuEntry _ Menus.CreateEntry[ -- which correspond to the "grid" things name: "Grat", proc: GridOnOff, clientData: NIL, documentation: "Draw time graticule" ]; shotEntry: Menus.MenuEntry _ Menus.CreateEntry[ name: "I.P.", proc: IPBut, clientData: NIL, documentation: "Creates Interpress master" ]; activeEntry: Menus.MenuEntry _ Menus.CreateEntry[ name: "Active", proc: Freeze, clientData: true, documentation: "Stops interactive refresh" ]; frozenEntry: Menus.MenuEntry _ Menus.CreateEntry[ name: "Frozen", proc: Freeze, clientData: false, documentation: "Stops interactive refresh" ]; sizeXEntry: Menus.MenuEntry _ Menus.CreateEntry[ name: "sizeX", proc: ScaleX, clientData: NIL, documentation: "Zoom X" ]; magSizeEntry: Menus.MenuEntry _ Menus.CreateEntry[ name: "MagSizeX", proc: MagScaleX, clientData: NIL, documentation: "Zoom X mag" ]; sizeYEntry: Menus.MenuEntry _ Menus.CreateEntry[ name: "sizeY", proc: ScaleY, clientData: NIL, documentation: "Zoom Y" ]; magEntry: ARRAY BOOLEAN OF Menus.MenuEntry _ [magOffEntry, magOnEntry]; liasonEntry: ARRAY BOOLEAN OF Menus.MenuEntry _ [frozenEntry, activeEntry]; graphColorList: LIST OF Color _ LIST[black, red, green, blue, puce]; selection: LIST OF REF ANY _ NIL; xAxisName: REAL _ 2.0; yAxisName: REAL _ -charHeight-2.0; ViewerOps.RegisterViewerClass[$PlotGViewer, plotGPictureClass];-- Register with viewers END.