DIRECTORY Icons USING [IconFlavor, NewIconFromFile], Imager USING [ConstantColor, Context], InputFocus USING [SetInputFocus], MessageWindow USING [Append], Graph USING [ColorIndex, GraphColorsArray, GraphFontsArray, ValueList, Viewer], GraphCarets USING [GetFocus, SetFocus], GraphCleanUp USING [CleanUpHandle], GraphPrivate USING [BackgroundIndex, ChartMenus, Draw, EraseSelEntity, EraseSelText, GraphHandle, GraphProc, JumpDownAnyCurve, JumpLeftAnyCurve, JumpLeftSameCurve, JumpRightAnyCurve, JumpRightSameCurve, JumpUpAnyCurve, Lock, MoveSelText, MoveXhair2To1, OutputType, PaintAll, PaintInfo, SelectPoint, SelectEntity, SelectText, ShowSelEntityOnPanel, ShowSelTextOnPanel, SlideLeftNSteps, SlideOnSameCurve, SlideRightNSteps, SwitchAuto, SwitchCaretBlinking, SwitchCaretVisibility, SwitchGrid, SwitchTarget, Unlock, Wait, ZoomIn, ZoomOut, ZoomPoint], GraphUtil USING [HandleFromViewer, HandleNotNil, ReplaceFileExt, SetCursorForBackgroundIndex, UseDefaultColors], Process USING [Abort], Rope USING [Cat, Equal, ROPE], TIPUser USING [InstantiateNewTIPTable, TIPScreenCoords], UserProfile USING [CallWhenProfileChanges, ProfileChangedProc, Token], ViewerClasses USING [Column, NotifyProc, PaintProc, PaintRectangle, Viewer, ViewerClass, ViewerClassRec], ViewerEvents USING [EventProc, RegisterEventProc], ViewerOps USING [CreateViewer, EnumerateViewers, EnumProc, OpenIcon, PaintViewer, RegisterViewerClass, SwapIconAndViewer, TopViewer], WindowManager USING [colorDisplayOn]; GraphViewer: CEDAR PROGRAM IMPORTS Icons, InputFocus, MessageWindow, GraphCarets, GraphCleanUp, GraphPrivate, GraphUtil, Process, Rope, TIPUser, UserProfile, ViewerEvents, ViewerOps, WindowManager EXPORTS GraphPrivate = { OPEN Graph, GraphPrivate, GraphUtil; chartIcon: Icons.IconFlavor _ Icons.NewIconFromFile["Graph.icons", 0]; graphViewerClass: ViewerClasses.ViewerClass _ NEW [ViewerClasses.ViewerClassRec _ [paint: GraphPaint, icon: chartIcon, cursor: textPointer, tipTable: TIPUser.InstantiateNewTIPTable["Graph.TIP"], notify: GraphNotify ]]; initialColumn: ViewerClasses.Column; -- {static, left, right, color} createOption: {closeOtherViewers, swapLastViewer, iconic, badCreateOption}; backgroundIndex: BackgroundIndex; -- {white, gray, darkGray, black, unknown} defaultColorsArray: PUBLIC GraphColorsArray _ [ [R: 1.0, G: 1.0, B: 1.0], -- 0, white, reserved for color cursor, foreground or background. [R: 1.0, G: 0.0, B: 0.8], -- 1, purple red [R: 0.4, G: 0.0, B: 1.0], -- 2, purple [R: 0.0, G: 0.0, B: 1.0], -- 3, blue [R: 0.0, G: 0.56, B: 1.0], -- 4, greenish blue [R: 0.0, G: 1.0, B: 1.0], -- 5, green blue [R: 0.0, G: 1.0, B: 0.0], -- 6, green [R: 0.52, G: 1.0, B: 0.0], -- 7, yellow green [R: 1.0, G: 1.0, B: 0.0], -- 8, yellow [R: 1.0, G: 0.60, B: 0.0], -- 9, orange yellow [R: 1.0, G: 0.42, B: 0.0], -- 10, yellowish orange [R: 1.0, G: 0.25, B: 0.0], -- 11, orange [R: 1.0, G: 0.0, B: 0.0], -- 12, red [R: 0.5, G: 0.5, B: 0.5], -- 13, gray, reserved for background. (default target color.) [R: 0.17, G: 0.17, B: 0.17], -- 14, dark gray, reserved for background. [R: 0.0, G: 0.0, B: 0.0] -- 15, black, reserved for color cursor, foreground or background. ]; defaultFontsArray: PUBLIC GraphFontsArray _ [ ["TimesRoman", FALSE, FALSE, 8, 9.0], -- 0, TimesRoman8, reserved. ["TimesRoman", TRUE, FALSE, 12, 13.0], -- 4, 12b, reserved. ["TimesRoman", FALSE, TRUE, 8, 9.0], -- 1, ~8i ["TimesRoman", TRUE, FALSE, 8, 9.0], -- 2, ~8b ["TimesRoman", FALSE, FALSE, 6, 7.0], -- 3, ~6 ["Helvetica", FALSE, FALSE, 8, 9.0], -- 5, Helvetica8 ["Helvetica", FALSE, FALSE, 6, 7.0], -- 6, ~6 ["Helvetica", TRUE, FALSE, 14, 15.0], -- 7, ~14b ["Gacha", FALSE, FALSE, 8, 9.0], -- 8, Gacha8 ["Hippo", FALSE, FALSE, 8, 9.0], -- 9, Hippo8 ["Logo", FALSE, FALSE, 12, 14.0], -- 10, Logo12 ["Math", FALSE, FALSE, 8, 9.0] -- 11, Math8, reserved. ]; systemColor: PUBLIC ARRAY ColorIndex OF Imager.ConstantColor; ShowChart: PUBLIC GraphProc = { IF HandleNotNil[handle] THEN { OPEN handle; viewer: Viewer _ chart.viewer; IF viewer = NIL THEN NewChartViewer[handle] ELSE { Unlock[handle]; IF viewer.iconic THEN ViewerOps.OpenIcon[icon: viewer, bottom: FALSE] ELSE ViewerOps.TopViewer[viewer]; }; }; }; -- ShowChart NewChartViewer: GraphProc = { OPEN handle; viewer: Viewer _ chart.viewer _ ViewerOps.CreateViewer[ flavor: $Graph, info: [ class: graphViewerClass, name: ReplaceFileExt[graph.fileName, "graph"], menu: ChartMenus[], column: initialColumn, iconic: TRUE, data: handle], paint: FALSE]; Unlock[handle]; SELECT createOption FROM iconic => ViewerOps.PaintViewer[viewer, all, TRUE, NIL]; closeOtherViewers => ViewerOps.OpenIcon[icon: viewer, closeOthers: TRUE, bottom: TRUE, paint: TRUE]; swapLastViewer => { vLast: Viewer _ NIL; LastViewer: ViewerOps.EnumProc = { IF v.column = initialColumn AND NOT v.iconic THEN {vLast _ v; RETURN[FALSE]}; }; -- LastViewer ViewerOps.EnumerateViewers[LastViewer]; IF vLast = NIL THEN ViewerOps.OpenIcon[icon: viewer, closeOthers: TRUE, bottom: TRUE, paint: TRUE] ELSE { ViewerOps.SwapIconAndViewer[icon: viewer, openViewer: vLast, paint: TRUE]; -- this paints the new viewer only. ViewerOps.PaintViewer[vLast, all, TRUE, NIL]; -- paint the last viewer. }; }; ENDCASE; }; -- NewChartViewer IsGraphViewer: PUBLIC PROC [viewer: Viewer] RETURNS [BOOL] = { IF viewer = NIL THEN RETURN[FALSE]; RETURN[viewer.class.flavor = $Graph]; }; -- IsGraphViewer GraphPaint: ViewerClasses.PaintProc = { IF IsGraphViewer[self] AND context # NIL AND NOT self.iconic THEN { handle: GraphHandle _ HandleFromViewer[self]; IF handle # NIL THEN { OPEN handle; IF whatChanged # NIL AND ISTYPE[whatChanged, PaintInfo] THEN { paintInfo.output _ screen; Draw[context, handle]; } ELSE { Lock[handle]; paintInfo.output _ screen; paintInfo.action _ paint; IF whatChanged = NIL THEN paintInfo.item _ all ELSE IF ISTYPE[whatChanged, ViewerClasses.PaintRectangle] THEN { vr: ViewerClasses.PaintRectangle _ NARROW[whatChanged]; paintInfo.item _ rectangle; paintInfo.rect _ [vr.x, vr.y, vr.w, vr.h]; }; Draw[context, handle]; waitingGraph _ FALSE; Unlock[handle]; }; }; -- handle # nil }; }; -- GraphPaint GraphBeforeDestroy: ViewerEvents.EventProc = { handle: GraphHandle _ HandleFromViewer[viewer]; IF handle # NIL AND event=destroy AND IsGraphViewer[viewer] AND before THEN { Lock[handle]; IF GraphCarets.GetFocus[] = handle THEN GraphCarets.SetFocus[NIL]; IF handle.selectProc # NIL THEN { TRUSTED {Process.Abort[handle.selectProc]}; Unlock[handle]; UNTIL handle.selectProc = NIL DO Wait[]; ENDLOOP; Lock[handle]; }; handle.chart.viewer _ NIL; Unlock[handle]; }; }; -- GraphBeforeDestroy GraphAfterDestroy: ViewerEvents.EventProc = { handle: GraphHandle _ HandleFromViewer[viewer]; IF handle # NIL AND event=destroy AND IsGraphViewer[viewer] AND NOT before THEN { Lock[handle]; IF handle.controller = NIL THEN handle _ GraphCleanUp.CleanUpHandle[handle, TRUE] ELSE Unlock[handle]; }; }; -- GraphAfterDestroy GraphNotify: ViewerClasses.NotifyProc= { IF IsGraphViewer[self] AND NOT self.iconic THEN { handle: GraphHandle _ HandleFromViewer[self]; IF HandleNotNil[handle] THEN { mx, my: INTEGER; nArg: INT; FOR params: LIST OF REF ANY _ input, params.rest UNTIL params = NIL DO Lock[handle]; WITH params.first SELECT FROM xy: TIPUser.TIPScreenCoords => { mx _ xy.mouseX; my _ xy.mouseY; }; n: REF LONG INTEGER => nArg _ n^; a: ATOM => { SELECT a FROM $SetFocus => InputFocus.SetInputFocus[handle.chart.viewer]; $SelectText => SelectText[handle, mx, my]; $Slide => SlideOnSameCurve[handle, mx, my]; $SelectCurve => SelectEntity[handle, mx, my]; $SelectPoint => SelectPoint[handle, mx, my]; $ZoomPoint => ZoomPoint[handle, mx, my]; $ShowSelTextOnPanel => ShowSelTextOnPanel[handle]; $ShowSelEntityOnPanel => ShowSelEntityOnPanel[handle]; $JumpLeftSameCurve => JumpLeftSameCurve[handle]; $JumpLeftAnyCurve => JumpLeftAnyCurve[handle]; $JumpUp => JumpUpAnyCurve[handle]; $ZoomIn => ZoomIn[handle, mx, my]; $LeftStep => SlideLeftNSteps[handle, nArg]; $RemoveCurve => EraseSelEntity[handle]; $JumpRightSameCurve => JumpRightSameCurve[handle]; $JumpRightAnyCurve => JumpRightAnyCurve[handle]; $ClearText => EraseSelText[handle]; $MoveSelText => MoveSelText[handle, mx, my]; $JumpDown => JumpDownAnyCurve[handle]; $ZoomOut => ZoomOut[handle, mx, my]; $RightStep => SlideRightNSteps[handle, nArg]; $PrimaryVisibility, $SecondaryVisibility, $TextCaretVisibility => SwitchCaretVisibility[handle, SELECT a FROM $PrimaryVisibility => primary, $SecondaryVisibility => secondary, ENDCASE => text ]; $PrimaryBlinking, $SecondaryBlinking, $TextCaretBlinking => SwitchCaretBlinking[handle, SELECT a FROM $PrimaryBlinking => primary, $SecondaryBlinking => secondary, ENDCASE => text ]; $SaveCrosshair => MoveXhair2To1[handle]; $ToggleAutoBounds => SwitchAuto[handle, bounds]; $ToggleAutoDiv => SwitchAuto[handle, divisions]; $ToggleTargetX, $ToggleTargetY => SwitchTarget[handle, IF a = $ToggleTargetX THEN x ELSE y]; $ToggleGridX, $ToggleGridY => SwitchGrid[handle, IF a = $ToggleGridX THEN x ELSE y]; $CleanAndPaint => PaintAll[handle, TRUE]; $Repaint => PaintAll[handle, FALSE]; ENDCASE; }; ENDCASE; Unlock[handle]; ENDLOOP; }; }; }; -- GraphNotify ProcessUserProfile: PUBLIC UserProfile.ProfileChangedProc = { rope: Rope.ROPE _ UserProfile.Token[key: "Graph.Column", default: "color"]; initialColumn _ SELECT TRUE FROM rope.Equal["color", FALSE] => color, rope.Equal["left", FALSE] => left, rope.Equal["right", FALSE] => right, ENDCASE => static; IF initialColumn = static THEN { MessageWindow.Append[ Rope.Cat["Warning: Illegal entry in user profile, Graph.Column: ", rope, "."], TRUE]; initialColumn _ color; }; IF initialColumn = color AND NOT WindowManager.colorDisplayOn THEN initialColumn _ left; rope _ UserProfile.Token[key: "Graph.CreateOption", default: "closeOtherViewers"]; createOption _ SELECT TRUE FROM rope.Equal["closeOtherViewers", FALSE] => closeOtherViewers, rope.Equal["swapLastViewer", FALSE] => swapLastViewer, rope.Equal["iconic", FALSE] => iconic, ENDCASE => badCreateOption; IF createOption = badCreateOption THEN { MessageWindow.Append[ Rope.Cat["Warning: Illegal entry in user profile, Graph.CreateOption: ", rope, "."], TRUE]; createOption _ closeOtherViewers; }; rope _ UserProfile.Token[key: "Graph.Background", default: "white"]; backgroundIndex _ SELECT TRUE FROM rope.Equal["white", FALSE] => white, rope.Equal["gray", FALSE] => gray, rope.Equal["darkGray", FALSE] => darkGray, rope.Equal["black", FALSE] => black, ENDCASE => unknown; IF backgroundIndex = unknown THEN { MessageWindow.Append[ Rope.Cat["Warning: Illegal entry in user profile, Graph.Background: ", rope, "."], TRUE]; backgroundIndex _ white; }; IF reason = firstTime THEN UseDefaultColors[]; SetCursorForBackgroundIndex[backgroundIndex]; }; -- ProcessUserProfile Init: PROC [] = { ViewerOps.RegisterViewerClass[$Graph, graphViewerClass]; [] _ ViewerEvents.RegisterEventProc[proc: GraphBeforeDestroy, event: destroy, before: TRUE]; [] _ ViewerEvents.RegisterEventProc[proc: GraphAfterDestroy, event: destroy, before: FALSE]; ProcessUserProfile[firstTime]; UserProfile.CallWhenProfileChanges[ProcessUserProfile]; GraphCarets.SetFocus[NIL]; }; -- Init Init[]; }. CHANGE LOG. SChen, October 19, 1985 10:09:23 pm PDT, created. BFile: GraphViewer.mesa, Copyright (C) 1985 by Xerox Corporation. All rights reserved. Last Edited by: Sweetsun Chen, October 21, 1985 7:52:08 pm PDT FS USING [ExpandName, GetDefaultWDir], (constant) variables destroy: GraphDestroy parameters initialized or updated by ProcessUserProfile entity colors: all vivid gray or black [family, bold, italic, vFontSize, pFontScale] public procedures if graph viewer already exists, then pop it up to the top; else create the viewer for the graph on the handle. Supposed to be locked before this is called. This proc will unlock handle before paintproc is to be invoked. inhibitDestroy: inhibitDestroy, AddEntity: PUBLIC PROC [viewer: Viewer _ NIL, entity: Entity _ NIL] = { IF vector = NIL OR NOT IsGraphViewer[viewer] THEN RETURN ELSE { shouldPaint: BOOL _ FALSE; expectedSize: CARDINAL; handle: GraphHandle _ NARROW[viewer.data]; IF handle # NIL THEN { Lock[handle]; expectedSize _ handle.graphSpec.nCurvesMax + 1; IF vector.size # expectedSize THEN MessageWindow.Append[ IO.PutFR["Only %g elements in vector when %g expected.", IO.int[vector.size], IO.int[expectedSize]], TRUE] ELSE { IF handle.curves = NIL THEN { handle.lineStates _ NEW[StateSequence[handle.graphSpec.nCurvesMax]]; Note: lineStates[n] is the state of curve # n+1. FOR i: CARDINAL IN[0..handle.graphSpec.nCurvesMax) DO handle.lineStates[i] _ NEW[LineStateRec _ []]; ENDLOOP; } ELSE IF handle.curves.first # NIL THEN shouldPaint _ TRUE; handle.curves _ CONS[vector, handle.curves] }; Unlock[handle]; }; IF shouldPaint THEN ViewerOps.PaintViewer[viewer, client, FALSE, handle.curves]; }; }; -- AddEntity other private procedures [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] there is no checking of the viewer class in Draw. GraphOpen: ViewerEvents.EventProc = { handle: GraphHandle _ HandleFromViewer[viewer]; IF handle # NIL AND event = open AND IsGraphViewer[viewer] AND NOT before THEN handle.graphOpened _ TRUE; }; -- GraphOpen initialColumn createOption backgroundType colors [] _ ViewerEvents.RegisterEventProc[proc: GraphOpen, event: open, before: FALSE]; Ê j˜JšœV™Všœ™Jšœ.™.J™—šÏk ˜ Jšœ&™&Jšœœ˜*Jšœœ˜&Jšœ œ˜!Jšœœ ˜JšœœD˜OJšœ œ˜'Jšœ œ˜#Jšœ œŽ˜ Jšœ œa˜pJšœœ ˜Jšœœœ˜Jšœœ+˜8Jšœ œ5˜FJšœœW˜jJšœ œ ˜2Jšœ œv˜…Jšœœ˜%J˜—šœ œ˜Jšœ¢˜©Jšœœ ˜=—J˜Jšœ™JšœF˜Fšœ.œ ˜QJšœ˜Jšœ˜Jšœ˜Jšœ6˜6Jšœ˜Jšœ™Jšœ˜—J™Jšœ7™7Jšœ%Ïc˜DJšœK˜KJšœ"ž*˜LJ˜šœœ˜/šœžA˜]J™—Jšœž˜,Jšœž ˜(Jšœž ˜&Jšœž˜/Jšœž˜,Jšœž ˜'Jšœž˜.Jšœž ˜(Jšœž˜/Jšœž˜3Jšœž ˜)šœž ˜&J™ —Jšœž=˜YJšœž*˜GJšœžB˜^J˜J˜—šœœ˜-Jšœ-™-Jšœœœ ž˜BJšœœœ ž˜;Jšœœœ ž ˜.Jšœœœ ž ˜.Jšœœœ ž˜.J˜Jšœœœ ž˜5Jšœœœ ž˜-Jšœœœ ž ˜0J˜Jšœ œœ ž ˜-Jšœ œœ ž ˜-Jšœ œœ ž ˜/Jšœ œœ ž˜6J˜J˜—Jšœ œœ œ˜=J˜Jšœ™J˜šÏn œœ˜J™:J™3J™mšœœœ˜+Jšœ˜Jšœ œœ˜+šœ˜J˜Jšœœ*œ˜EJšœ˜!J˜—J˜—Jšœž ˜J˜šŸœœ˜*šœ7˜7J˜šœ˜Jšœ˜Jšœ.˜.Jšœ˜Jšœ˜Jšœœ˜ J™Jšœ˜—Jšœœ˜—J˜J˜šœ˜Jšœ-œœ˜8šœ5˜5Jšœ œ œ œ˜.—šœ˜Jšœœ˜˜"Jš œœœ œ œœ˜MJšœž ˜—J˜'J˜šœ œœ!˜4Jšœ œ œ œ˜-—šœ˜šœ)˜)Jšœœž#˜D—Jšœ"œœž˜GJ˜—J˜—Jšœ˜—Jšœž˜——J˜š Ÿ œœœœœ™Gšœ œœœœœœ™?Jšœ œœ™Jšœœ™Jšœœ™*šœ œœ™J™ Jšœ/™/šœœ™8Jšœ6™8Jšœœœ™1—šœ™šœœœ™šœœ-™DJšœ0™0—šœœœ!™5Jšœœ™.Jšœ™—J™—Jš œœœœœ™:Jšœœ™+J™—J™J™—Jšœ œ'œ™PJ™—Jšœž ™J˜—š Ÿ œœœœœ˜>Jš œ œœœœ˜#Jšœ˜%Jšœž˜—J˜Jšœ™šœ'˜'JšœJ™Jš œœ œœœ œ˜CJšœ1™1Jšœ-˜-šœ œœœ˜#š œœœœœ˜>J˜Jšœ˜J˜—šœ˜Jšœ ˜ J˜J˜Jšœœœ˜.šœœœ,œ˜@Jšœ#œ˜7J˜Jšœ*˜*J˜—Jšœ˜Jšœœ˜Jšœ˜J˜—Jšœž˜—J˜—Jšœž ˜J˜—šœ.˜.Jšœ/˜/š œ œœœœœ˜MJ˜ Jšœ!œœ˜Bšœœœ˜!Jšœ$˜+J˜Jšœœœ œ˜1J˜ J˜—Jšœœ˜J˜J˜—Jšœž˜—J˜šœ-˜-Jšœ/˜/šœ œœœœœœ˜QJ˜ Jšœœœ-œ˜QJšœ˜J˜—Jšœž˜J˜—šœ%™%Jšœ/™/š œ œœœœœ™NJšœœ™—šœž ™J™——šœ(˜(šœœœ œ˜1J˜-šœœ˜Jšœœ˜Jšœœ˜ šœ œœœœœ œ˜FJ˜ šœœ˜˜ Jšœ˜Jšœ˜J˜—Jšœœœœ˜!šœœ˜ šœ˜ J˜;Jšœ*˜*Jšœ+˜+Jšœ-˜-Jšœ,˜,Jšœ(˜(Jšœ2˜2Jšœ6˜6Jšœ0˜0Jšœ.˜.Jšœ"˜"Jšœ"˜"Jšœ+˜+Jšœ'˜'Jšœ2˜2Jšœ0˜0Jšœ#˜#J˜,Jšœ&˜&Jšœ$˜$Jšœ-˜-šœA˜Ašœœ˜+JšœA˜AJšœ˜Jšœ˜——šœ;˜;šœœ˜)Jšœ=˜=Jšœ˜Jšœ˜——Jšœ(˜(Jšœ0˜0Jšœ0˜0šœ"˜"Jšœœœœ˜:—šœ˜Jšœœœœ˜6—Jšœ#œ˜)Jšœœ˜$Jšœ˜—J˜—Jšœ˜—J˜Jšœ˜—J˜—J˜—Jšœž˜J˜—šœœ#˜=Jšœ ™ Jšœ œ<˜Kšœœœ˜ Jšœœ ˜$Jšœœ ˜"Jšœœ ˜$Jšœ ˜—šœœ˜ šœ˜JšœN˜NJšœ˜—Jšœ˜J˜—Jšœœœœ˜XJ˜Jšœ ™ JšœR˜Ršœœœ˜Jšœ œ˜