ScannerInterfaceImpl.mesa
Copyright (C) 1985, Xerox Corporation. All rights reserved.
Last edited by Tim Diebert: May 12, 1986 1:54:31 pm PDT
Tim Diebert : May 29, 1985 12:23:01 pm PDT
DIRECTORY
AISViewer USING [CreateAISViewer, DisplayAIS, ProgressProc, RPProc],
Buttons USING [ButtonProc, Create, ReLabel, SetDisplayStyle],
Commander USING [CommandProc, Handle, Register],
CommandTool USING [CurrentWorkingDirectory],
Containers USING [ChildXBound, ChildYBound, Container, Create],
Convert USING [Error, CardFromRope],
Eikonix USING [NBufferRecord, IntegrationTime, LineCount, PixelIndex, LineIndex, PixelCount],
FileNames USING [FileWithSearchRules],
FS USING [ExpandName],
Icons USING [IconFlavor, NewIconFromFile],
IO USING [card, GetTokenRope, IDProc, EndOfStream, PutFR, PutRope, RIS, STREAM],
Labels USING [Create],
List USING [Append, Assoc],
PieViewers USING [Create, Set],
Real USING [RoundC],
Rope USING [IsEmpty, Equal, Length, ROPE],
Rules USING [Create, Rule],
TypeScript USING [Create],
UserProfile USING [CallWhenProfileChanges],
VFonts USING [CharWidth],
ViewerClasses USING [Viewer],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [PaintViewer],
ViewerTools USING [GetContents, InhibitUserEdits, MakeNewTextViewer, SelPosRec, SetContents, SetSelection],
VM USING [CantAllocate],
ScannerInternal
;
ScannerInterfaceImpl: CEDAR PROGRAM
IMPORTS AISViewer, Buttons, Commander, CommandTool, Containers, Convert, FileNames, FS, Icons, IO, Labels, List, PieViewers, Real, Rope, Rules, ScannerInternal, TypeScript, UserProfile, VFonts, ViewerIO, ViewerOps, ViewerTools, VM
EXPORTS
~ BEGIN
OPEN Tool: ScannerInternal;
ROPE: TYPE ~ Rope.ROPE;
STREAM: TYPE ~ IO.STREAM;
c1: INT = 80;
c2: INT = 120;
c3: INT = 170;
c4: INT = 285;
c5: INT = 350;
c6: INT = 400;
c7: INT = 460;
c8: INT = 520;
c210: INT = 210;
c300: INT = 300;
minFeedbackLines: INT = 3;
NewScanner: PROC [iconic: BOOL, wDir: ROPE, cmd: Commander.Handle] = BEGIN
tool: Tool.Tool;
ruleH: INT ← 0;
scanB: INT ← 0;
AddSeparatingRule: PROC = BEGIN
rule: Rules.Rule = Rules.Create[info: [
wx: 0,
wy: tool.height,
ww: 9999, -- arbitrary; Containers.ChildXBound overrides
wh: 1,
parent: tool.outer
]];
Containers.ChildXBound[tool.outer, rule]; -- constrain rule to be width of parent
tool.height ← tool.height + tool.params.entryVSpace; -- spacing after rule
END;
BuildFileInfo: PROC = BEGIN
prev: ViewerClasses.Viewer;
prev ← Buttons.Create[
info: [name: "File:",
wx: tool.params.entryHSpace,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: FALSE
],
proc: SelectFileName,
fork: FALSE,
clientData: tool,
guarded: FALSE,
font: tool.params.font
];
tool.fileNameViewer ← ViewerTools.MakeNewTextViewer[info: [
wx: prev.wx + prev.ww + tool.params.entryHSpace,
wy: tool.height,
ww: c6 - (prev.ww + prev.wx) - 5,
wh: tool.params.entryHeight,
parent: tool.outer,
scrollable: TRUE,
border: FALSE
]];
prev ← Buttons.Create[
info: [name: "WD:",
wx: c6,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: FALSE
],
proc: SelectWDName,
fork: FALSE,
clientData: tool,
guarded: FALSE,
font: tool.params.font
];
tool.wDirViewer ← ViewerTools.MakeNewTextViewer[info: [
wx: prev.wx + prev.ww + tool.params.entryHSpace,
wy: tool.height,
ww: VFonts.CharWidth['M, tool.params.font] * 12,
wh: tool.params.entryHeight,
data: wDir,
parent: tool.outer,
scrollable: FALSE,
border: FALSE
]];
ruleH ← tool.height ← tool.height + tool.params.entryHeight + tool.params.entryVSpace;
AddSeparatingRule[];
prev ← Labels.Create[
info: [name: "Scan Start:",
wx: tool.params.entryHSpace,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: FALSE
],
font: tool.params.font
];
tool.scanStartViewer ← ViewerTools.MakeNewTextViewer[info: [
wx: c1,
wy: tool.height,
ww: VFonts.CharWidth['0, tool.params.font] * 7,
wh: tool.params.entryHeight,
data: "0",
parent: tool.outer,
scrollable: FALSE,
border: FALSE
]];
prev ← Labels.Create[
info: [name: "Scans:",
wx: c2,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: FALSE
],
font: tool.params.font
];
tool.scansViewer ← ViewerTools.MakeNewTextViewer[info: [
wx: c3,
wy: tool.height,
ww: c210 - c3 - 1,
wh: tool.params.entryHeight,
data: "2048",
parent: tool.outer,
scrollable: FALSE,
border: FALSE
]];
prev ← Buttons.Create[
info: [name: "Abort",
wx: 220,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: TRUE
],
proc: Abort,
fork: TRUE,
clientData: tool,
guarded: TRUE,
font: tool.params.font
];
prev ← Buttons.Create[
info: [name: "SampleScan",
wx: prev.wx + prev.ww + tool.params.entryHSpace/2,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: TRUE
],
proc: SampleScan,
fork: TRUE,
clientData: tool,
guarded: FALSE,
font: tool.params.font
];
prev ← Buttons.Create[
info: [name: "Scan",
wx: (scanB ← prev.wx + prev.ww + tool.params.entryHSpace/2),
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: TRUE
],
proc: Scan,
fork: TRUE,
clientData: tool,
guarded: TRUE,
font: tool.params.font
];
prev ← Labels.Create[
info: [name: "At scan:",
wx: c6,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: FALSE
],
font: tool.params.font
];
tool.atScanViewer ← ViewerTools.MakeNewTextViewer[info: [
wx: c7,
wy: tool.height,
ww: VFonts.CharWidth['0, tool.params.font] * 7,
wh: tool.params.entryHeight,
data: "0",
parent: tool.outer,
scrollable: FALSE,
border: FALSE
]];
ViewerTools.InhibitUserEdits[tool.atScanViewer];
prev ← Buttons.Create[
info: [name: "Min/Max",
wx: c8,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: TRUE
],
proc: MinMax,
fork: FALSE,
clientData: tool,
guarded: FALSE,
font: tool.params.font
];
tool.height ← tool.height + tool.params.entryHeight + tool.params.entryVSpace;
END;
BuildNext: PROC [] = BEGIN
prev: ViewerClasses.Viewer;
h: INT ← tool.height;
prev ← Labels.Create[
info: [name: "Pixel Start:",
wx: tool.params.entryHSpace,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: FALSE
],
font: tool.params.font
];
tool.pixelStartViewer ← ViewerTools.MakeNewTextViewer[info: [
wx: c1,
wy: tool.height,
ww: VFonts.CharWidth['0, tool.params.font] * 7,
wh: tool.params.entryHeight,
data: "0",
parent: tool.outer,
scrollable: FALSE,
border: FALSE
]];
prev ← Labels.Create[
info: [name: "Pixels:",
wx: c2,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: FALSE
],
font: tool.params.font
];
tool.pixelsViewer ← ViewerTools.MakeNewTextViewer[info: [
wx: c3,
wy: tool.height,
ww: c210 - c3 - 1,
wh: tool.params.entryHeight,
data: "2048",
parent: tool.outer,
scrollable: FALSE,
border: FALSE
]];
tool.colorButton ← Buttons.Create[
info: [name: "Clear",
wx: 220,
wy: tool.height,
wh: tool.params.entryHeight,
ww: 40,
parent: tool.outer, 
border: FALSE
],
font: tool.params.font,
proc: ColorButtonPush,
fork: FALSE,
clientData: tool
];
tool.pieBW ← PieViewers.Create[parent: tool.outer, x: scanB, y: tool.height];
prev ← Buttons.Create[
info: [name: "Int Time:",
wx: c6,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: FALSE
],
font: tool.params.font,
proc: SelectIntTime,
fork: FALSE,
clientData: tool
];
tool.iTimeViewer ← ViewerTools.MakeNewTextViewer[info: [
wx: c7,
wy: tool.height,
ww: VFonts.CharWidth['0, tool.params.font] * 7,
wh: tool.params.entryHeight,
data: "4500",
parent: tool.outer,
scrollable: FALSE,
border: FALSE
]];
tool.iTime ← 4500;
prev ← Buttons.Create[
info: [name: "Calibrate",
wx: c8,
wy: tool.height,
wh: tool.params.entryHeight,
parent: tool.outer, 
border: TRUE
],
proc: Calibrate,
fork: TRUE,
clientData: tool,
guarded: TRUE,
font: tool.params.font
];
tool.height ← tool.height + tool.params.entryHeight + tool.params.entryVSpace;
AddSeparatingRule[];
[] ← Rules.Create[info: [
wx: c210,
wy: ruleH,
ww: 1,
wh: tool.height - ruleH - tool.params.entryVSpace,
parent: tool.outer
]];
[] ← Rules.Create[info: [
wx: c6 - 5,
wy: ruleH,
ww: 1,
wh: tool.height - ruleH - tool.params.entryVSpace,
parent: tool.outer
]];
END;
***Main Body of NewScanner***
empty, abort: BOOLEANFALSE;
iconName: ROPE; ambiguous: BOOL;
icon: Icons.IconFlavor;
pStream: IO.STREAMIO.RIS[cmd.commandLine];
p1: ROPE;
p1 ← IO.GetTokenRope[pStream, IO.IDProc
! IO.EndOfStream => {empty ← TRUE; CONTINUE}].token;
tool ← NEW[Tool.ToolRecord];
IF NOT empty AND NOT p1.IsEmpty[] THEN BEGIN-- P1 present
IF Rope.Equal[p1, "-c", FALSE]
THEN BEGIN -- calibration flag found
empty ← FALSE;
tool.scannerCalFile ← IO.GetTokenRope[pStream, IO.IDProc
! IO.EndOfStream => {empty ← TRUE; CONTINUE}].token;
IF empty OR tool.scannerCalFile.Length[] < 1
THEN -- no calibration filename found
tool.scannerCalFile ← NIL; -- use default rather than flag error
END
ELSE tool.scannerCalFile ← NIL;  -- filename found but no calibration flag found
END;
tool.searchRules ← List.Append[NARROW[List.Assoc[key: $SearchRules, aList: cmd.propertyList]]];
tool.busy ← TRUE;
tool.params ← Tool.GetToolParameters[];
[iconName, ambiguous] ← FileNames.FileWithSearchRules[root: "Scanner.icons", defaultExtension: "icons", searchRules: tool.searchRules];
icon ← Icons.NewIconFromFile[iconName, 0];
tool.outer ← Containers.Create[
info: [
name: "Scanner Tool", iconic: TRUE, column: left, scrollable: FALSE, icon: icon
],
paint: TRUE
];
tool.outer.inhibitDestroy ← TRUE;
tool.height ← tool.params.entryVSpace;
BuildFileInfo[];
BuildNext[];
PieViewers.Set[tool.pieBW, 0];
tool.logViewer ← TypeScript.Create[
info: [
wx: 0,
wy: tool.height + 5,
ww: 9999,
wh: minFeedbackLines * tool.params.entryHeight - 6,
parent: tool.outer,
border: FALSE]
];
tool.height ← tool.height + minFeedbackLines * tool.params.entryHeight + tool.params.entryVSpace;
tool.out ← ViewerIO.CreateViewerStreams[name: "Scanner.log", viewer: tool.logViewer].out;
Containers.ChildXBound[container: tool.outer, child: tool.logViewer];
ViewerTools.InhibitUserEdits[tool.logViewer];
AddSeparatingRule[];
tool.AISViewer ← AISViewer.CreateAISViewer[
info: [
wx: 0,
wy: tool.height + 5,
ww: 9999,
wh: 9999,
parent: tool.outer,
border: FALSE]];
Containers.ChildXBound[container: tool.outer, child: tool.AISViewer];
Containers.ChildYBound[container: tool.outer, child: tool.AISViewer];
ViewerOps.PaintViewer[tool.outer, all];
IF tool.scannerCalFile.IsEmpty[] THEN tool.scannerCalFile ← tool.params.calFileName;
Tool.LoadCalFile[tool ! ABORTED => {abort ← TRUE; CONTINUE}];
IF abort THEN BEGIN
tool.dc ← NEW [Eikonix.NBufferRecord ← ALL [0]];
tool.gain ← NEW [Eikonix.NBufferRecord ← ALL [800H]];
FOR c: Tool.Color IN Tool.Color DO
tool.colorDC[c] ← NEW [Eikonix.NBufferRecord ← ALL [0]];
tool.colorGain[c] ← NEW [Eikonix.NBufferRecord ← ALL [800H]];
ENDLOOP;
END;
ViewerTools.SetContents[tool.iTimeViewer, IO.PutFR["%g", IO.card[tool.iTime]]];
tool.out.PutRope["Ready.\n"];
tool.busy ← FALSE;
tool.outer.inhibitDestroy ← FALSE;
END;
rspp: AISViewer.RPProc = BEGIN OPEN IO, Real, ViewerTools;
RPProc: TYPE =
PROC
[scanStart, pixelStart, scans, pixels: REAL, clientData: REF ANYNIL];
tool: Tool.Tool ← NARROW[clientData];
SetContents[tool.scanStartViewer, PutFR["%g", card[RoundC[scanStart * 16.0]]]];
SetContents[tool.pixelStartViewer, PutFR["%g", card[RoundC[pixelStart * 16.0]]]];
SetContents[tool.scansViewer, PutFR["%g", card[RoundC[scans * 16.0]]]];
SetContents[tool.pixelsViewer, PutFR["%g", card[RoundC[pixels * 16.0]]]];
END;
Abort: Buttons.ButtonProc ~ BEGIN
tool: Tool.Tool ← NARROW[clientData];
tool.abort ← TRUE;
END;
SampleScan: Buttons.ButtonProc ~ BEGIN
tool: Tool.Tool ← NARROW[clientData];
IF tool.busy THEN RETURN;
tool.busy ← TRUE;
BEGIN -- For ABORTED
ENABLE ABORTED => GOTO Out;
fn: ROPE ← ViewerTools.GetContents[tool.fileNameViewer];
wDir: ROPE ← ViewerTools.GetContents[tool.wDirViewer];
fullFName: ROPEFS.ExpandName[fn, wDir].fullFName;
IF fn.IsEmpty[] THEN {tool.out.PutRope["Set file name.\n"]; RETURN};
Tool.SampleScanToAisFile[tool, fullFName, tool.iTime];
tool.out.PutRope["Displaying .. "];
[] ← AISViewer.DisplayAIS[tool.AISViewer, fn, wDir, TRUE, NIL, rspp, tool
! VM.CantAllocate => {tool.out.PutRope["Out of VM "]; GOTO Out}];
tool.out.PutRope["Done\n"];
tool.busy ← FALSE;
EXITS Out => {tool.out.PutRope[" Aborted\n"]; tool.busy ← FALSE; RETURN};
END;
END;
pp: AISViewer.ProgressProc = BEGIN
ProgressProc: TYPE =
PROC
[scanStart, pixelStart, scans, pixels: CARDINAL, clientData: REF ANYNIL];
tool: Tool.Tool ← NARROW[clientData];
ViewerTools.SetContents[tool.scanStartViewer, IO.PutFR["%g", IO.card[scanStart]]];
ViewerTools.SetContents[tool.pixelStartViewer, IO.PutFR["%g", IO.card[pixelStart]]];
ViewerTools.SetContents[tool.scansViewer, IO.PutFR["%g", IO.card[scans]]];
ViewerTools.SetContents[tool.pixelsViewer, IO.PutFR["%g", IO.card[pixels]]];
END;
Scan: Buttons.ButtonProc ~ BEGIN
tool: Tool.Tool ← NARROW[clientData];
IF tool.busy THEN RETURN;
tool.busy ← TRUE;
BEGIN -- For ABORTED
ENABLE ABORTED => GOTO Out;
fn: ROPE ← ViewerTools.GetContents[tool.fileNameViewer];
wDir: ROPE ← ViewerTools.GetContents[tool.wDirViewer];
fullFName: ROPEFS.ExpandName[fn, wDir].fullFName;
scanStart, pixelStart, scans, pixels: CARDINAL;
IF fn.IsEmpty[] THEN {tool.out.PutRope["Set file name.\n"]; RETURN};
[scanStart, pixelStart, scans, pixels] ← GetScansAndStuff[tool];
Tool.ScanToAisFile[tool, fullFName, tool.iTime, tool.color, scanStart, pixelStart, scans, pixels];
tool.out.PutRope["Displaying .. "];
[] ← AISViewer.DisplayAIS[tool.AISViewer, fn, wDir, FALSE, NIL, NIL, tool
! VM.CantAllocate => {tool.out.PutRope["Out of VM "]; GOTO Out}];
tool.out.PutRope["Done\n"];
tool.busy ← FALSE;
EXITS Out => {tool.out.PutRope["Aborted\n"]; tool.busy ← FALSE; RETURN};
END;
END;
GetScansAndStuff: PROC
[tool: Tool.Tool] RETURNS [scanStart, pixelStart, scans, pixels: CARDINAL] = BEGIN
OPEN Convert, ViewerTools;
ENABLE Convert.Error => {tool.out.PutRope["Scns/Pixels Convert Error"]; ERROR ABORTED};
lc: LONG CARDINAL;
lc ← CardFromRope[GetContents[tool.scanStartViewer]];
IF lc NOT IN Eikonix.LineIndex THEN {tool.out.PutRope["Scan start out of range"]; ABORTED};
scanStart ← lc;
lc ← CardFromRope[GetContents[tool.pixelStartViewer]];
IF lc NOT IN Eikonix.PixelIndex THEN {tool.out.PutRope["Pixel start out of range"]; ABORTED};
pixelStart ← lc;
lc ← CardFromRope[GetContents[tool.scansViewer]];
IF lc NOT IN Eikonix.LineCount THEN {tool.out.PutRope["Scans out of range"]; ABORTED};
scans ← lc;
lc ← CardFromRope[GetContents[tool.pixelsViewer]];
IF lc NOT IN Eikonix.PixelCount THEN {tool.out.PutRope["Pixels out of range"]; ABORTED};
pixels ← lc;
lc ← CardFromRope[GetContents[tool.iTimeViewer]];
IF lc NOT IN Eikonix.IntegrationTime
THEN {tool.out.PutRope["ITime out of range"]; ABORTED}
ELSE tool.iTime ← lc;
END;
Calibrate: Buttons.ButtonProc = BEGIN
tool: Tool.Tool ← NARROW[clientData];
BEGIN -- For ABORTED
ENABLE ABORTED => GOTO Out;
IF tool.busy THEN RETURN;
tool.busy ← TRUE;
[] ← GetScansAndStuff[tool];
Tool.Calibrate[tool];
tool.busy ← FALSE;
EXITS Out => {tool.out.PutRope["Aborted\n"]; tool.busy ← FALSE; RETURN};
END;
END;
MinMax: Buttons.ButtonProc = BEGIN
tool: Tool.Tool ← NARROW[clientData];
IF tool.doMinMaxPreScan THEN {tool.doMinMaxPreScan ← FALSE;
Buttons.SetDisplayStyle[NARROW[parent], $BlackOnWhite];}
ELSE {tool.doMinMaxPreScan ← TRUE;
Buttons.SetDisplayStyle[NARROW[parent], $WhiteOnBlack]};
END;
ColorButtonPush: Buttons.ButtonProc = BEGIN
tool: Tool.Tool ← NARROW[clientData];
SELECT tool.color FROM
Clear => {tool.color ← Red; Buttons.ReLabel[tool.colorButton, "Red"]};
Red => {tool.color ← Green; Buttons.ReLabel[tool.colorButton, "Green"]};
Green => {tool.color ← Blue; Buttons.ReLabel[tool.colorButton, "Blue"]};
Blue => {tool.color ← Clear; Buttons.ReLabel[tool.colorButton, "Clear"]};
Opaque => ERROR;
ENDCASE => ERROR;
END;
SelectIntTime: Buttons.ButtonProc = BEGIN
[parent: REF ANY, clientData: REF ANYNIL, mouseButton: MouseButton ← red, shift, control: BOOLFALSE];
tool: Tool.Tool ← NARROW[clientData];
BEGIN -- For ABORTED
ENABLE ABORTED => GOTO Out;
IF mouseButton = red
THEN ViewerTools.SetSelection[tool.iTimeViewer]
ELSE Tool.LoadCalFile[tool];
EXITS Out => {tool.out.PutRope["Aborted\n"]; tool.busy ← FALSE; RETURN};
END;
END;
SelectFileName: Buttons.ButtonProc = BEGIN
tool: Tool.Tool ← NARROW[clientData];
ViewerTools.SetSelection[tool.fileNameViewer];
END;
SelectWDName: Buttons.ButtonProc = BEGIN
tool: Tool.Tool ← NARROW[clientData];
ViewerTools.SetSelection[tool.wDirViewer];
END;
MakeNewScanner: Commander.CommandProc = BEGIN
wDir: ROPE ← CommandTool.CurrentWorkingDirectory[];
NewScanner[TRUE, wDir, cmd];
END;
UserProfile.CallWhenProfileChanges[Tool.ReactToProfile];
Commander.Register["Scanner", MakeNewScanner, "Generate a new Scanner Tool"];
END.