GraphCaretsImpl.mesa, Copyright © 1985 by Xerox Corporation. All rights reserved.
Reference: CaretsImpl.mesa
Last edited:
Sweetsun Chen, November 15, 1985 5:45:48 pm PST
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;
vars
caretBits: ARRAY CaretIndex OF CaretBits;
graphFocus: GraphHandle ← NIL;
caretHoldCount: INTEGER ← 0; -- number of requests pending to suspend caret
TurnOn: PUBLIC ENTRY PROC [handle: GraphHandle ← NIL, index: CaretIndex ← primary] = {
ENABLE UNWIND => NULL;
IF HandleNotNil[handle] THEN On[handle, index];
}; -- TurnOn
TurnOff: PUBLIC ENTRY PROC [handle: GraphHandle ← NIL, index: CaretIndex ← primary] = {
ENABLE UNWIND => NULL;
IF HandleNotNil[handle] THEN Off[handle, index];
}; -- TurnOn
Move: PUBLIC ENTRY PROC [handle: GraphHandle ← NIL, x, y: INTEGER ← 0, index: CaretIndex ← primary, ensureOn: BOOLFALSE] = {
if mustTurnOn then make sure it's turned on, otherwise doesn't affect its visibility.
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 ← NIL] = {
ENABLE UNWIND => NULL;
IF HandleNotNil[handle] THEN FOR index: CaretIndex IN CaretIndex DO
On[handle, index];
ENDLOOP;
}; -- AllOn
AllOff: PUBLIC ENTRY PROC [handle: GraphHandle ← NIL] = {
ENABLE UNWIND => NULL;
IF HandleNotNil[handle] THEN FOR index: CaretIndex IN CaretIndex DO
Off[handle, index];
ENDLOOP;
}; -- AllOff
StartBlinking: PUBLIC ENTRY PROC [handle: GraphHandle ← NIL, index: CaretIndex ← primary] = { -- also turn it on.
ENABLE UNWIND => NULL;
IF HandleNotNil[handle] THEN {OPEN handle;
chart.caretState[index].toBlink ← TRUE;
On[handle, index];
};
}; -- StartBlinking
StopBlinking: PUBLIC ENTRY PROC [handle: GraphHandle ← NIL, 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 ← NIL] = {
ENABLE UNWIND => NULL;
graphFocus ← handle;
};
Suspend: PUBLIC ENTRY PROC[] = {
ENABLE UNWIND => NULL;
InternalSuspend[];
}; -- Suspend
Resume: PUBLIC ENTRY PROC = {
ENABLE UNWIND => NULL;
InternalResume[];
}; -- Resume
On: INTERNAL PROC [handle: GraphHandle, index: CaretIndex ← primary] = {
sets handle.graph.caret[index].on, and update display on chart accordingly.
Just turn it on. But it may not be blinking.
OPEN handle;
Appear[chart, index];
graph.caret[index].on ← TRUE;
}; -- On
Off: INTERNAL PROC [handle: GraphHandle ← NIL, 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[] = {
IF graphFocus # NIL THEN FOR index: CaretIndex IN CaretIndex DO
Disappear[graphFocus.chart, index];
ENDLOOP;
caretHoldCount ← caretHoldCount+1;
}; -- InternalSuspend
InternalResume: INTERNAL PROC = {
IF caretHoldCount > 0 THEN caretHoldCount ← caretHoldCount - 1;
IF graphFocus # NIL THEN FOR index: CaretIndex IN CaretIndex DO
IF graphFocus.graph.caret[index].on THEN Appear[graphFocus.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: BOOLFALSE;
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];
IF HandleNotNil[graphFocus] THEN IF graphFocus.chart.dirty THEN {
Lock[graphFocus];
InternalSuspend[];
PaintAll[graphFocus, FALSE];
InternalResume[];
Unlock[graphFocus];
};
}
ELSE {
make sure all on carets are visible.
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
ChangeCaretShape: PROC [index: CaretIndex, bits: TerminalDefs.Cursor];
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