<> <> <> <> <<>> DIRECTORY GraphCarets, Graph USING [CaretIndex, CaretState, Chart, GraphHandle], GraphOps USING [Lock, Unlock], GraphPrivate USING [IsGraphViewer, IsLocked], GraphUtil USING [HandleFromViewer, HandleNotNil, InViewer], Imager USING [Color, Context, MaskBits, SetColor], ImagerBackdoor USING [invert], InputFocus USING [GetInputFocus], Process USING [Detach, MsecToTicks, SecondsToTicks, SetTimeout], TerminalDefs USING [Cursor], ViewerClasses USING [Viewer], ViewerOps USING [UserToScreenCoords], ViewerPrivate USING [PaintScreen, Screen, ViewerScreen]; GraphCaretsImpl: CEDAR MONITOR IMPORTS GraphOps, GraphPrivate, GraphUtil, Imager, ImagerBackdoor, InputFocus, Process, ViewerOps, ViewerPrivate EXPORTS GraphCarets = { OPEN Graph, GraphOps, GraphPrivate, GraphUtil; blinkCondition: CONDITION; focusCondition: CONDITION; caretH, caretW: INTEGER = 16; caretXOffset, caretYOffset: CARDINAL = 8; CaretBits: TYPE ~ REF CaretBitsRep; -- ARRAY [0..16) OF WORD CaretBitsRep: TYPE = TerminalDefs.Cursor; <> caretBits: ARRAY CaretIndex OF CaretBits; graphFocus: GraphHandle _ NIL; caretHoldCount: INTEGER _ 0; -- number of requests pending to suspend caret TurnOn: PUBLIC ENTRY PROC [handle: GraphHandle, index: CaretIndex _ primary] = { ENABLE UNWIND => NULL; IF HandleNotNil[handle] THEN On[handle, index]; }; -- TurnOn TurnOff: PUBLIC ENTRY PROC [handle: GraphHandle, index: CaretIndex _ primary] = { ENABLE UNWIND => NULL; IF HandleNotNil[handle] THEN Off[handle, index]; }; -- TurnOn Move: PUBLIC ENTRY PROC [handle: GraphHandle, x, y: INTEGER _ 0, index: CaretIndex _ primary, ensureOn: BOOL _ FALSE] = { <> ENABLE UNWIND => NULL; IF HandleNotNil[handle] THEN { OPEN handle; Disappear[chart, index]; -- erase old caret, if visible. chart.caretState[index].x _ x; chart.caretState[index].y _ y; IF ensureOn THEN On[handle, index]; }; }; -- Move AllOn: PUBLIC ENTRY PROC [handle: GraphHandle] = { ENABLE UNWIND => NULL; IF HandleNotNil[handle] THEN FOR index: CaretIndex IN CaretIndex DO On[handle, index]; ENDLOOP; }; -- AllOn AllOff: PUBLIC ENTRY PROC [handle: GraphHandle] = { ENABLE UNWIND => NULL; IF HandleNotNil[handle] THEN FOR index: CaretIndex IN CaretIndex DO Off[handle, index]; ENDLOOP; }; -- AllOff StartBlinking: PUBLIC ENTRY PROC [handle: GraphHandle, index: CaretIndex _ primary] = { -- also turn it on, if not on yet. ENABLE UNWIND => NULL; IF HandleNotNil[handle] THEN {OPEN handle; chart.caretState[index].toBlink _ TRUE; On[handle, index]; }; }; -- StartBlinking StopBlinking: PUBLIC ENTRY PROC [handle: GraphHandle, index: CaretIndex _ primary] = { ENABLE UNWIND => NULL; IF HandleNotNil[handle] THEN {OPEN handle; IF graph.caret[index].on AND chart.caretState[index].toBlink THEN Appear[chart, index]; chart.caretState[index].toBlink _ FALSE; }; }; -- StopBlinking GetFocus: PUBLIC ENTRY PROC [] RETURNS [handle: GraphHandle _ NIL] = { ENABLE UNWIND => NULL; RETURN[graphFocus]; }; SetFocus: PUBLIC ENTRY PROC [handle: GraphHandle] = { ENABLE UNWIND => NULL; graphFocus _ handle; }; Suspend: PUBLIC ENTRY PROC [handle: GraphHandle] = { ENABLE UNWIND => NULL; InternalSuspend[handle]; }; -- Suspend Resume: PUBLIC ENTRY PROC [handle: GraphHandle] = { ENABLE UNWIND => NULL; InternalResume[handle]; }; -- Resume On: INTERNAL PROC [handle: GraphHandle, index: CaretIndex _ primary] = { <> <> OPEN handle; Appear[chart, index]; graph.caret[index].on _ TRUE; }; -- On Off: INTERNAL PROC [handle: GraphHandle, index: CaretIndex _ primary] = { OPEN handle; Disappear[chart, index]; graph.caret[index].on _ FALSE; }; -- Off Disappear: INTERNAL PROC [chart: Chart, index: CaretIndex] = { IF chart.caretState[index].visible THEN Invert[chart, index]; }; -- Disappear Appear: INTERNAL PROC [chart: Chart, index: CaretIndex] = { IF NOT chart.caretState[index].visible THEN Invert[chart, index]; }; -- Appear InternalSuspend: INTERNAL PROC [handle: GraphHandle] = { IF HandleNotNil[handle] THEN FOR index: CaretIndex IN CaretIndex DO Disappear[handle.chart, index]; ENDLOOP; caretHoldCount _ caretHoldCount+1; }; -- InternalSuspend InternalResume: INTERNAL PROC [handle: GraphHandle] = { IF caretHoldCount > 0 THEN caretHoldCount _ caretHoldCount - 1; IF HandleNotNil[handle] THEN FOR index: CaretIndex IN CaretIndex DO OPEN handle; IF graph.caret[index].on THEN Appear[chart, index]; ENDLOOP; }; -- InternalResume Invert: INTERNAL PROC [chart: Chart, index: CaretIndex] = { ENABLE UNWIND => NULL; viewer: ViewerClasses.Viewer _ chart.viewer; caret: CaretState _ chart.caretState[index]; IF InViewer[viewer, caret.x, caret.y] THEN { screen: ViewerPrivate.Screen ~ ViewerPrivate.ViewerScreen[viewer]; InvertAction: PROC [context: Imager.Context] ~ { sx, sy: INTEGER; [sx, sy] _ ViewerOps.UserToScreenCoords[viewer, caret.x, caret.y]; Imager.SetColor[context, ImagerBackdoor.invert]; Imager.MaskBits[context: context, base: LOOPHOLE[caretBits[index]], wordsPerLine: 1, sMin: 0, fMin: 0, sSize: caretH, fSize: caretW, tx: sx-caretXOffset, ty: sy+caretYOffset]; caret.visible _ NOT caret.visible; }; -- InvertAction ViewerPrivate.PaintScreen[screen: screen, action: InvertAction, suspendCarets: FALSE]; }; }; -- Invert GraphCaretsProcess: ENTRY PROC = { ENABLE UNWIND => NULL; suspended: BOOL _ FALSE; TRUSTED {Process.SetTimeout[@blinkCondition, Process.MsecToTicks[500]]}; DO WAIT blinkCondition; IF caretHoldCount # 0 THEN suspended _ TRUE -- suspended ELSE IF suspended THEN suspended _ FALSE ELSE IF graphFocus # NIL THEN { IF NOT IsLocked[graphFocus] THEN { Lock[graphFocus]; FOR index: CaretIndex IN CaretIndex DO IF graphFocus.graph.caret[index].on AND graphFocus.chart.caretState[index].toBlink THEN Invert[graphFocus.chart, index]; ENDLOOP; Unlock[graphFocus]; }; }; ENDLOOP; }; -- GraphCaretsProcess GraphFocusProcess: ENTRY PROC = { ENABLE UNWIND => NULL; TRUSTED {Process.SetTimeout[@focusCondition, Process.SecondsToTicks[2]]}; DO viewer: ViewerClasses.Viewer; WAIT focusCondition; viewer _ InputFocus.GetInputFocus[].owner; IF IsGraphViewer[viewer] THEN { graphFocus _ HandleFromViewer[viewer]; <> <> <> <> <> <> <<};>> } ELSE { <> IF graphFocus # NIL THEN IF graphFocus.chart.viewer # NIL THEN FOR i: CaretIndex IN CaretIndex DO IF graphFocus.graph.caret[i].on THEN Appear[graphFocus.chart, i]; ENDLOOP; graphFocus _ NIL; }; ENDLOOP; }; -- GraphFocusProcess <<>> <> <<>> Init: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; graphFocus _ NIL; caretBits _ [ NEW[CaretBitsRep _ [ 000400B, -- 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 000400B, 000400B, 000400B, 000400B, 000400B, 000400B, 177776B, -- 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 000400B, 000400B, 000400B, 000400B, 000400B, 000400B, 000400B, 0]], -- primary crosshair NEW[CaretBitsRep _ [ 000400B, 0, 000400B, 0, 000400B, 0, 000400B, 125252B, -- 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 000400B, 0, 000400B, 0, 000400B, 0, 000400B, 0]], -- secondary crosshair NEW[CaretBitsRep _ [ 000400B, -- 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 040404B, -- 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 020410B, -- 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 010420B, -- 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 004440B, -- 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0 0 002500B, -- 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 001600B, -- 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 177776B, -- 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 001600B, -- 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 002500B, -- 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 004440B, -- 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0 0 010420B, -- 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 020410B, -- 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 040404B, -- 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 000400B, -- 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]] -- text caret ]; TRUSTED { Process.Detach[FORK GraphCaretsProcess]; -- start the blinker Process.Detach[FORK GraphFocusProcess]; }; }; -- Init }. CHANGE LOG. SChen, August 30, 1985 1:38:10 pm PDT, created taking reference of CaretsImpl.mesa