DIRECTORY Icons USING [IconFlavor, NewIconFromFile], Imager USING [ConstantColor, Context], InputFocus USING [SetInputFocus], Graph USING [BackgroundIndex, CaretIndex, ColorIndex, GraphColors, GraphColorsArray, GraphFonts, GraphFontsArray, GraphHandle, GraphProc, OutputType, PaintInfo, PaintInfoRec, ROPE, ValueList, Viewer], GraphCarets USING [GetFocus, Init, SetFocus], GraphCleanUp USING [CleanUpHandle], GraphOps USING [Lock, Unlock], GraphPrivate USING [ChartMenus, Draw, EraseSelEntity, EraseSelText, JumpDownAnyCurve, JumpLeftAnyCurve, JumpLeftSameCurve, JumpRightAnyCurve, JumpRightSameCurve, JumpUpAnyCurve, MoveSelText, MoveXhair2To1, PaintAll, RemoveAllCurves, RotateSelTextCCW, RotateSelTextCW, SelectPoint, SelectEntity, SelectText, ShowSelEntityOnSpec, ShowSelTextOnSpec, SlideLeftNSteps, SlideOnSameCurve, SlideRightNSteps, SwitchAuto, SwitchCaretBlinking, SwitchCaretVisibility, SwitchGrid, SwitchTarget, UserEditAllowed, Wait, ZoomIn, ZoomOut, ZoomPoint], GraphUtil USING [HandleFromViewer, HandleNotNil, SetCursorForBackgroundIndex, UseDefaultColors, UseMyColors, UseMyFonts], Process USING [Abort], Rope USING [Equal], 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, GraphCarets, GraphCleanUp, GraphOps, GraphPrivate, GraphUtil, Process, Rope, TIPUser, UserProfile, ViewerEvents, ViewerOps, WindowManager EXPORTS GraphPrivate = { OPEN Graph, GraphOps, GraphPrivate, GraphUtil; graphIcon: Icons.IconFlavor _ Icons.NewIconFromFile["Graph.icons", 0]; graphViewerClass: ViewerClasses.ViewerClass _ NEW [ViewerClasses.ViewerClassRec _ [paint: GraphPaint, icon: graphIcon, cursor: textPointer, tipTable: TIPUser.InstantiateNewTIPTable["Graph.TIP"], notify: GraphNotify ]]; initialColumn: ViewerClasses.Column; -- {static, left, right, color} createOption: {closeOtherViewers, swapLastViewer, iconic, badCreateOption, open}; backgroundIndex: BackgroundIndex; -- {white, gray, darkGray, black, unknown} defaultColors: PUBLIC GraphColors _ NEW[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.0], -- 1, red [R: 0.0, G: 1.0, B: 0.0], -- 2, green [R: 0.0, G: 0.0, B: 1.0], -- 3, blue [R: 1.0, G: 1.0, B: 0.0], -- 4, yellow [R: 1.0, G: 0.25, B: 0.0], -- 5, orange [R: 0.4, G: 0.0, B: 1.0], -- 6, purple [R: 0.0, G: 1.0, B: 1.0], -- 7, green blue [R: 1.0, G: 0.0, B: 0.8], -- 8, purple red [R: 1.0, G: 0.60, B: 0.0], -- 9, orange yellow [R: 0.0, G: 0.56, B: 1.0], -- 10, greenish blue [R: 1.0, G: 0.42, B: 0.0], -- 11, yellowish orange [R: 0.52, G: 1.0, B: 0.0], -- 12, yellow green [R: 0.75, G: 0.75, B: 0.75], -- 13, gray, reserved for background. (default target color.) [R: 0.25, G: 0.25, B: 0.25], -- 14, dark gray, reserved for background. [R: 0.0, G: 0.0, B: 0.0] -- 15, black, reserved for color cursor, foreground or background. ]]; defaultFonts: PUBLIC GraphFonts _ NEW[GraphFontsArray _ [ ["TimesRoman", FALSE, FALSE, 10, 11.0], -- 0, TimesRoman10, reserved. ["TimesRoman", FALSE, FALSE, 8, 9.0], -- 1, TimesRoman8, reserved. ["TimesRoman", TRUE, FALSE, 12, 13.0], -- 2, 12b, reserved. ["TimesRoman", FALSE, TRUE, 10, 11.0], -- 3, ~10i ["TimesRoman", TRUE, FALSE, 10, 11.0], -- 4, ~10b ["Helvetica", FALSE, FALSE, 10, 11.0], -- 5, Helvetica8 ["Helvetica", TRUE, FALSE, 14, 15.0], -- 6, Helvetica14b ["Gacha", FALSE, FALSE, 10, 11.0], -- 7, Gacha10 ["Gacha", FALSE, FALSE, 8, 9.0], -- 8, Gacha8 ["Hippo", FALSE, FALSE, 10, 11.0], -- 9, Hippo10 ["Logo", FALSE, FALSE, 14, 15.0], -- 10, Logo14 ["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 { UseMyColors[handle]; UseMyFonts[handle]; NewChartViewer[handle]; } ELSE { 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: graph.fileName, menu: ChartMenus[], column: initialColumn, iconic: TRUE, data: handle], paint: TRUE]; SELECT createOption FROM iconic => { }; open => ViewerOps.OpenIcon[viewer]; 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; info: PaintInfo; IF whatChanged = NIL THEN { FOR i: CaretIndex IN CaretIndex DO chart.caretState[i].visible _ FALSE; ENDLOOP; info _ NEW[all PaintInfoRec _ [data: all[clear: TRUE, updateDivBds: FALSE]]]; } ELSE IF ISTYPE[whatChanged, PaintInfo] THEN { info _ NARROW[whatChanged]; info.output _ screen; } ELSE IF ISTYPE[whatChanged, ViewerClasses.PaintRectangle] THEN { vr: ViewerClasses.PaintRectangle _ NARROW[whatChanged]; info _ NEW[rectangle PaintInfoRec _ [data: rectangle[ clear: NOT clear, updateDivBds: FALSE, rect: [vr.x, vr.y, vr.w, vr.h]]]]; } ELSE info _ NEW[all PaintInfoRec _ [data: all[clear: NOT clear]]]; -- what is it ? Draw[handle, context, info]; IF whatChanged = NIL THEN { mergingBounds _ FALSE; }; }; -- 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]; $ShowSelTextOnSpec => ShowSelTextOnSpec[handle]; $ShowSelEntityOnSpec => ShowSelEntityOnSpec[handle]; $JumpLeftSameCurve => JumpLeftSameCurve[handle]; $JumpLeftAnyCurve => JumpLeftAnyCurve[handle]; $JumpUp => JumpUpAnyCurve[handle]; $ZoomIn => ZoomIn[handle, mx, my]; $LeftStep => SlideLeftNSteps[handle, nArg]; $RemoveCurve => IF UserEditAllowed[handle] THEN EraseSelEntity[handle]; $RemoveAllCurves => IF UserEditAllowed[handle] THEN RemoveAllCurves[handle]; $JumpRightSameCurve => JumpRightSameCurve[handle]; $JumpRightAnyCurve => JumpRightAnyCurve[handle]; $ClearText => EraseSelText[handle]; $RotateSelTextCW => RotateSelTextCW[handle, nArg]; $RotateSelTextCCW => RotateSelTextCCW[handle, nArg]; $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, FALSE, TRUE]; $Repaint => PaintAll[handle, FALSE, FALSE, TRUE]; ENDCASE; }; ENDCASE; Unlock[handle]; ENDLOOP; }; }; }; -- GraphNotify ProcessUserProfile: PUBLIC UserProfile.ProfileChangedProc = { 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 => color; IF initialColumn = color AND NOT WindowManager.colorDisplayOn THEN initialColumn _ left; rope _ UserProfile.Token[key: "Graph.CreateOption", default: "open"]; createOption _ SELECT TRUE FROM rope.Equal["closeOtherViewers", FALSE] => closeOtherViewers, rope.Equal["swapLastViewer", FALSE] => swapLastViewer, rope.Equal["iconic", FALSE] => iconic, ENDCASE => open; 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 => gray; 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.Init[]; }; -- Init Init[]; }. CHANGE LOG. SChen, October 19, 1985 10:09:23 pm PDT, created. Jacobi, June 11, 1986 6:43:10 pm PDT, Added normal option of viewer creation nFile: GraphViewer.mesa, Copyright (C) 1985 by Xerox Corporation. All rights reserved. Last Edited by: Pradeep Sindhu April 8, 1986 6:39:17 pm PST Sweetsun Chen, April 23, 1986 2:30:35 pm PST Christian Jacobi, June 11, 1986 6:43:46 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. No more, 11/13/85. waitingGraph _ TRUE; WHILE waitingGraph DO Wait[]; ENDLOOP; Unlock[handle]; inhibitDestroy: inhibitDestroy, Unlock[handle]; ViewerOps.PaintViewer[viewer, all, TRUE, NIL]; waitingGraph _ FALSE; 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. screen must have been cleared by the Viewers package, so we should make sure that the caretState's are not confused. (action: paint, output: screen) IF clear THEN WITH info SELECT FROM a: REF all PaintInfoRec => a.clear _ FALSE; r: REF rectangle PaintInfoRec => r.clear _ FALSE; ENDCASE; 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šœV™Všœ™Icode™+Jšœ,™,Jšœ.™.J™—šΟk ˜ Jšœ&™&Jšœœ˜*Jšœœ˜&Jšœ œ˜!Jšœœ€œ˜ΘJšœ œ˜-Jšœ œ˜#Jšœ œ˜Jšœ œƒ˜•Jšœ œj˜yJšœœ ˜Jšœœ ˜Jšœœ+˜8Jšœ œ5˜FJšœœW˜jJšœ œ ˜2Jšœ œv˜…Jšœœ˜%J˜—šœ œ˜Jšœ˜€Jšœœ*˜G—J˜Jšœ™JšœF˜Fšœ.œ ˜QJšœ˜Jšœ˜Jšœ˜Jšœ6˜6Jšœ˜Jšœ™Jšœ˜—J™Jšœ7™7Jšœ%Οc˜DJšœQ˜QJšœ"ž*˜LJ˜šœœœ˜<šœžA˜]J™—Jšœž ˜%Jšœž ˜'Jšœž ˜&Jšœž ˜(Jšœž ˜(Jšœž ˜(Jšœž˜,Jšœž˜,Jšœž˜/Jšœž˜0Jšœž˜3šœž˜/J™ —Jšœž=˜\Jšœž*˜GJšœžB˜^J˜J˜—šœœœ˜9Jšœ-™-Jšœœœ ž˜EJšœœœ ž˜BJšœœœ ž˜;Jšœœœ ž ˜1Jšœœœ ž ˜1J˜Jšœœœ ž˜7Jšœœœ ž˜8J˜Jšœ œœ ž ˜0Jšœ œœ ž ˜-Jšœ œœ ž ˜0Jšœ œœ ž ˜/Jšœ œœ ž˜6J˜J˜—Jšœ œœ œ˜=J˜Jšœ™J˜šœ œ˜J™:J™3J™,J™Ršœœœ˜+Jšœ˜šœ œœ˜J˜J˜Jšœœ™Jšœ˜Jšœœ œ™&J˜—šœ˜J™Jšœœ*œ˜EJšœ˜!J˜—J˜—Jšœž ˜J˜šœœ˜*šœ7˜7J˜šœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœœ˜ J™Jšœ˜—Jšœœ˜ —J˜J™šœ˜šœ ˜ Jšœ#œœ™.Jšœœ™J˜—Jšœ#˜#šœ5˜5Jšœ œ œ œ˜.—šœ˜Jšœœ˜˜"Jš œœœ œ œœ˜MJšœž ˜—J˜'J˜šœ œœ!˜4Jšœ œ œ œ˜-—šœ˜šœ)˜)Jšœœž#˜D—Jšœ"œœž˜GJ˜—J˜—Jšœ˜—Jšœž˜——J˜š Οn œœœœœ™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™tšœœ ˜"Jšœœ˜$Jšœ˜—šœœ&œœ˜MJšœ™—J˜—šœœœœ˜-Jšœœ˜Jšœ˜š œœœœ™#Jšœœœ™+Jšœœ%œ™1Jšœ™—J˜—šœœœ,œ˜@Jšœ#œ˜7šœœ+˜5Jšœœœ$˜I—J˜—Jšœœ&œ ž˜RJšœ˜šœœœ˜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šœ0˜0Jšœ4˜4Jšœ0˜0Jšœ.˜.Jšœ"˜"Jšœ"˜"Jšœ+˜+Jšœœœ˜GJšœœœ˜LJšœ2˜2Jšœ0˜0Jšœ#˜#Jšœ2˜2Jšœ4˜4Jšœ,˜,Jšœ&˜&Jšœ$˜$Jšœ-˜-šœA˜Ašœœ˜+JšœA˜AJšœ˜Jšœ˜——šœ;˜;šœœ˜)Jšœ=˜=Jšœ˜Jšœ˜——Jšœ(˜(Jšœ0˜0Jšœ0˜0šœ"˜"Jšœœœœ˜:—šœ˜Jšœœœœ˜6—Jšœ#œœœ˜6Jšœœœœ˜1Jšœ˜—J˜—Jšœ˜—J˜Jšœ˜—J˜—J˜—Jšœž˜J˜—šœœ#˜=Jšœ ™ Jšœœ<˜Fšœœœ˜ Jšœœ ˜$Jšœœ ˜"Jšœœ ˜$Jšœ ˜—Jšœœœœ˜XJ˜Jšœ ™ JšœE˜Ešœœœ˜Jšœ œ˜