-- BuildTRCImpl.mesa
-- Mik Lamming - December 11, 1984 1:22:03 pm PST
DIRECTORY Icons, Convert, Hist, Terminal, Buttons, FS, IO, RealFns, ColorMap, MessageWindow, UserProfile, Commander, Containers, Real, Rope, Rules, TRCViewer, ViewerTools, UPOps, ViewerClasses ;
BuildTRCImpl: CEDAR MONITOR
IMPORTS Icons, Real, Convert, Terminal, Buttons, Hist, FS, IO, ColorMap, RealFns, MessageWindow, UserProfile, Commander, Containers, Rules, TRCViewer, UPOps, Rope, ViewerTools
SHARES Terminal
= BEGIN
LogFlag: Rope.ROPE ← "Log";
LinFlag: Rope.ROPE ← "Linear";
vt: Terminal.Virtual;
DisplayState: TYPE = {bpp8, bpp24, off};
displayState: DisplayState ← off;
icon: Icons.IconFlavor ← Icons.NewIconFromFile["BuildTRC.icons", 0];
State: TYPE = REF StateRec;
StateRec: TYPE = RECORD [
container: ViewerClasses.Viewer,
linBut, logBut, negBut, shiftBut, rotateBut, initBut, simBut: Buttons.Button,
setHistWhite, setHistBlack, setGamma, setInputModeBut, setOutputModeBut: Buttons.Button,
showHistBut, calcHistBut, equaliseBut, histSourceBut, wdBut: Buttons.Button,
trcFileBut, saveTRCBut, getTRCBut: Buttons.Button,
inputScaleTypeIn, outputScaleTypeIn, histSourceTypeIn, wdTypeIn, trcFileTypeIn, whiteTypeIn, blackTypeIn, gammaTypeIn: ViewerClasses.Viewer,
trcViewer: ViewerClasses.Viewer,
wd: Rope.ROPE,
maxInputDens, maxOutputDens: REAL ← 99.0,
inputMode, outputMode: TRCViewer.FeedBackMode ← density,
connectMode: TRCViewer.ConnectMode ← linear,
histoOn: BOOLEANFALSE,
addVertexOnShiftOrRotate: BOOLEANFALSE,
histo: Hist.Histogram ← NIL,
simRed, simGrn, simBlu: BOOLEANTRUE,
gamma: REAL ← 2.2
];
Simulate: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
IF displayState=off THEN {
vt ← Terminal.Current[];
IF NOT vt.hasColorDisplay THEN displayState ← off
ELSE IF vt.colorMode.full THEN displayState𡤋pp24 ELSE displayState𡤋pp8;
UpdateColorMap[state];
Buttons.SetDisplayStyle[state.simBut, $WhiteOnBlack];
}
ELSE {
Buttons.SetDisplayStyle[state.simBut, $BlackOnWhite];
displayState ← off;
}
};
UpdateColorMap: PROC [state:State] ~ {
SetMap: PROC [entry:NAT, value:NAT] ~ {
reflectance:REAL;
IF state.outputMode=density THEN
reflectance ← RealFns.Power[10, - ((255 - value) / 255.0) * maxDensityOut]
ELSE
reflectance ← minROut + rangeR * value / 255.0;
SELECT displayState FROM
bpp8 => {
ColorMap.SetRGBColor[entry, reflectance, reflectance, reflectance];
};
bpp24 => {
SELECT value FROM
IN [1..254] => {
reflectance ← RealFns.Power[reflectance, oneOverGamma];
};
ENDCASE;
value ← MAX[MIN[255, Real.RoundC[reflectance*255]], 0];
IF state.simRed THEN Terminal.SetRedMap[vt, entry, value];
IF state.simGrn THEN Terminal.SetGreenMap[vt, entry, value];
IF state.simBlu THEN Terminal.SetBlueMap[vt, entry, value];
};
ENDCASE;
};
minROut, rangeR, maxDensityOut: REAL;
err: BOOLEAN;
oneOverGamma: REAL ;
IF displayState=off THEN RETURN [];
[state.gamma, err] ← GetRealFromViewer[state.gammaTypeIn];
IF err OR state.gamma <= 0 THEN {
MessageWindow.Append["Gamma should be > 0", TRUE];
MessageWindow.Blink[];
RETURN [];
};
IF displayState=bpp8 THEN ColorMap.SetGamma[state.gamma]
ELSE oneOverGamma ← 1 / state.gamma;
[maxDensityOut, err] ← GetDensityFromScaleViewer[state.outputScaleTypeIn, state.outputMode];
IF ~err THEN {
trc: Hist.TRCVec ← TRCViewer.Get[state.trcViewer];
minROut ← TRCViewer.DensToRef[maxDensityOut];
rangeR ← 1 - minROut;
FOR i: NAT IN [0..255] DO
SetMap[i, trc[i].out]
ENDLOOP;
};
};
FixUpMap: TRCViewer.ChangeProc ~ {
UpdateColorMap[NARROW[clientData]]
};
StartNewInstance: Commander.CommandProc ~ {
AddButton: PROC [label: Rope.ROPE, proc: Buttons.ButtonProc, left, top: NAT, width:NAT ← 0, clientData: REF ANY ← state]
RETURNS [b: Buttons.Button, right, bottom: NAT] ~ {
b ← Buttons.Create[
info: [
parent: state.container,
name: label,
wx: left,
wy: top,
ww:width
],
proc: proc,
clientData: clientData
];
RETURN [b, left+b.ww, top+b.wh]
};
AddTypeIn: PROC [left, top, width, height: NAT, init:Rope.ROPENIL] RETURNS [t: ViewerClasses.Viewer, right, bottom: NAT] ~ {
t ← ViewerTools.MakeNewTextViewer[
info:[
wx:left, wy:top, ww:width, wh:height,
parent: state.container,
border: FALSE,
scrollable: FALSE,
data: init]];
RETURN [t, left+t.ww, top+t.wh]
};
pStream: IO.STREAMIO.RIS[cmd.commandLine];
empty:BOOLEANFALSE;
p1: Rope.ROPE;
leftMargin: NAT ~ 2; row0: NAT ~ 2; colSep: NAT ~ 2; groupSep: NAT ~ 8; rowSep: NAT ~ 4;
scaleTypeInWidth: NAT ~ 85;
fileTypeInWidth: NAT ~ 160;
wdTypeInWidth: NAT ~ 260;
cardWidth: NAT ~ 40;
fileNameButTab, butHt, nextX, nextY, tempY : NAT ;
state: State ← NEW[StateRec];
p1 ← IO.GetTokenRope[pStream, IO.IDProc
! IO.EndOfStream => {
empty ← TRUE;
CONTINUE;
}].token;
state.simRed ← state.simGrn ← state.simBlu ← TRUE;
IF NOT empty AND Rope.Length[p1]>0 THEN { -- parameter present
SELECT TRUE FROM
Rope.Equal[p1, "-B", FALSE] => state.simRed ← state.simGrn ← FALSE;
Rope.Equal[p1, "-R", FALSE] => state.simBlu ← state.simGrn ← FALSE;
Rope.Equal[p1, "-G", FALSE] => state.simRed ← state.simBlu ← FALSE;
ENDCASE
};
ScanProfile[state];
state.container ← Containers.Create[info: [name:Rope.Cat["TRC Builder", p1], scrollable:FALSE, icon:icon]];
state.container.class.paintRectangles ← FALSE; -- disable viewers bug
state.container.class.bltContents ← none;
nextX ← leftMargin; nextY ← row0;
[state.linBut, nextX, tempY] ← AddButton["Linear", SetLinearMode, nextX, nextY];
Buttons.SetDisplayStyle[state.linBut, $WhiteOnBlack];
butHt ← tempY - row0;
[state.logBut, nextX, ] ← AddButton["Log", SetLogMode, nextX+colSep, nextY];
[state.negBut, nextX, ] ← AddButton["Negative", Negate, nextX+colSep, nextY];
[state.shiftBut, nextX, ] ← AddButton["Shift", Shift, nextX+colSep, nextY];
[state.rotateBut, nextX, ] ← AddButton["Rotate", Rotate, nextX+colSep, nextY];
[state.initBut, nextX, ] ← AddButton["Init", InitTRC, nextX+colSep, nextY];
[] ← Rules.Create[info:[wx:nextX+groupSep/2-1, wy:0, ww:2, wh:row0+butHt+1, parent:state.container]];
[state.simBut, nextX, ] ← AddButton["Simulate", Simulate, nextX+groupSep, nextY];
[] ← Rules.Create[info:[wx:nextX+groupSep/2-1, wy:0, ww:2, wh:row0+2*(butHt+3), parent:state.container]];
fileNameButTab ← nextX+groupSep;
[state.wdBut, nextX, ] ← AddButton["WD", SelectWD, fileNameButTab, nextY];
[state.wdTypeIn, nextX, nextY] ← AddTypeIn[fileNameButTab+40, nextY, wdTypeInWidth, butHt, state.wd];
FS.SetDefaultWDir[state.wd
! FS.Error => {
MessageWindow.Append[IO.PutFR["Bad WD: %g is not a local directory", IO.rope[state.wd]], TRUE];
MessageWindow.Blink[];
CONTINUE}];
[] ← Rules.Create[info:[wx:0, wy:nextY+1, ww:1000, wh:2, parent:state.container]];
nextY ← nextY + rowSep;
[state.setInputModeBut, nextX, ] ← AddButton["MaxDIn", SelectInScale, leftMargin, nextY];
[state.inputScaleTypeIn, nextX, ] ← AddTypeIn[nextX+colSep, nextY, scaleTypeInWidth, butHt, IO.PutFR["%g", IO.real[state.maxOutputDens]]];
[state.setOutputModeBut, nextX, ] ← AddButton["MaxDOut", SelectOutScale, nextX+colSep, nextY];
[state.outputScaleTypeIn, nextX, tempY] ← AddTypeIn[nextX+colSep, nextY, scaleTypeInWidth, butHt, IO.PutFR["%g", IO.real[state.maxInputDens]]];
[] ← Rules.Create[info:[wx:nextX+groupSep/2-1, wy:tempY+1, ww:1000, wh:2, parent:state.container]];
[state.trcFileBut, nextX, ] ← AddButton["TRC", SelectTRC, fileNameButTab, nextY];
[state.trcFileTypeIn, nextX, ] ← AddTypeIn[fileNameButTab+40, nextY, fileTypeInWidth, butHt];
[state.saveTRCBut, nextX, ] ← AddButton["Save", SaveTRC, nextX+colSep, nextY];
[state.getTRCBut, nextX, nextY] ← AddButton["Restore", ReadTRC, nextX+colSep, nextY];
[] ← Rules.Create[info:[wx:0, wy:nextY+1, ww:1000, wh:2, parent:state.container]];
nextY ← nextY + rowSep;
[] ← Rules.Create[info:[wx:nextX+groupSep/2-1, wy:tempY+1, ww:2, wh:-2*(butHt+rowSep), parent:state.container]];
[state.setGamma, nextX, ] ← AddButton["Gamma", SelGamma, leftMargin, nextY];
[state.gammaTypeIn, nextX, tempY] ← AddTypeIn[nextX+colSep, nextY, scaleTypeInWidth, butHt, IO.PutFR["%g", IO.real[state.gamma]]];
[] ← Rules.Create[info:[wx:nextX+1, wy:tempY+3, ww:2, wh:-(butHt+5), parent:state.container]];
[state.setHistBlack, nextX, ] ← AddButton["Black", SelBlack, nextX+6, nextY];
[state.blackTypeIn, nextX, ] ← AddTypeIn[nextX+colSep, nextY, cardWidth, butHt, "0"];
[state.setHistWhite, nextX, ] ← AddButton["White", SelWhite, nextX, nextY];
[state.whiteTypeIn, nextX, ] ← AddTypeIn[nextX+colSep, nextY, cardWidth, butHt, "255"];
[state.histSourceBut, nextX, ] ← AddButton["Hist", SelectHist, fileNameButTab, nextY];
[state.histSourceTypeIn, nextX, ] ← AddTypeIn[fileNameButTab+40, nextY, fileTypeInWidth, butHt];
[state.showHistBut, nextX, ] ← AddButton["Off", ToggleHisto, nextX+colSep, nextY];
[state.calcHistBut, nextX, ] ← AddButton["Calc", CalcHisto, nextX+colSep, nextY];
[state.equaliseBut, nextX, nextY] ← AddButton["Eq", Equalise, nextX+colSep, nextY];
[] ← Rules.Create[info:[wx:0, wy:nextY+1, ww:1000, wh:2, parent:state.container]];
state.trcViewer ← ViewerOps.CreateViewer[
flavor: $TRCViewer,
info: [
parent: state.container,
wx: leftMargin, wy: nextY+rowSep, ww:100, wh:100]];
Containers.ChildYBound[state.container, state.trcViewer];
Containers.ChildXBound[state.container, state.trcViewer];
TRCViewer.SetMaxDensityIn[state.trcViewer, state.maxInputDens];
TRCViewer.SetMaxDensityOut[state.trcViewer, state.maxOutputDens];
TRCViewer.RegisterChangeProc[state.trcViewer, FixUpMap, state];
};
ScanProfile: PROC [state:State] ~ {
tempRope: Rope.ROPE;
state.wd ← UserProfile.Token["BuildTRC.WD", NIL];
IF state.wd=NIL THEN
state.wd ← FS.GetDefaultWDir[];
state.maxInputDens ← Convert.RealFromRope[
tempRope ← UserProfile.Token[
"BuildTRC.MaxInputDensity", "3.0"] ! Convert.Error => {
MessageWindow.Append[IO.PutFR["Bad user profile entry for BuildTRC.MaxInputDensity: %g is not a valid real number", IO.rope[tempRope]], TRUE];
MessageWindow.Blink[];
state.maxInputDens ← 88.0;
CONTINUE;
}];
state.maxOutputDens ← Convert.RealFromRope[
tempRope ← UserProfile.Token[
"BuildTRC.MaxOutputDensity", "3.0"] ! Convert.Error => {
MessageWindow.Append[IO.PutFR["Bad user profile entry for BuildTRC.MaxOutputDensity: %g is not a valid real number", IO.rope[tempRope]], TRUE];
MessageWindow.Blink[];
state.maxOutputDens ← 88.0;
CONTINUE;
}];
state.gamma ← Convert.RealFromRope[
tempRope ← UserProfile.Token[
"BuildTRC.Gamma", "2.2"] ! Convert.Error => {
MessageWindow.Append[IO.PutFR["Bad user profile entry for BuildTRC.Gamma: %g is not a valid real number", IO.rope[tempRope]], TRUE];
MessageWindow.Blink[];
state.gamma ← 2.2;
CONTINUE;
}];
};
GetDensityFromScaleViewer: PROC [
v: ViewerClasses.Viewer,
mode: TRCViewer.FeedBackMode] RETURNS [d:REAL, err:BOOLEANFALSE] ~ {
r: REAL;
[r, err] ← GetRealFromViewer[v];
IF err THEN RETURN;
IF mode=density THEN {
IF r<0 THEN {
MessageWindow.Append["Scale value should be positive", TRUE];
MessageWindow.Blink[];
err ← TRUE;
}
ELSE {
d ← r;
};
}
ELSE
IF r<0 OR r>1 THEN {
MessageWindow.Append["Scale value should be [0..1]", TRUE];
MessageWindow.Blink[];
err ← TRUE;
}
ELSE {
d ← TRCViewer.RefToDens[r];
};
};
GetRealFromViewer: PROC [v: ViewerClasses.Viewer] RETURNS [r:REAL, err:BOOLEANFALSE] ~ {
rope: Rope.ROPE ← ViewerTools.GetContents[v];
in:IO.STREAMIO.RIS[rope];
r ← IO.GetReal[in !
IO.Error => {
MessageWindow.Append["Invalid format in real number specification", TRUE];
MessageWindow.Blink[];
err ← TRUE;
CONTINUE
};
IO.EndOfStream => {
MessageWindow.Append["Parameter absent", TRUE];
MessageWindow.Blink[];
err ← TRUE;
CONTINUE
}];
};
GetCardFromViewer: PROC [v: ViewerClasses.Viewer] RETURNS [r:NAT, err:BOOLEANFALSE] ~ {
rope: Rope.ROPE ← ViewerTools.GetContents[v];
in:IO.STREAMIO.RIS[rope];
r ← IO.GetCard[in !
IO.Error => {
MessageWindow.Append["Invalid format in number specification", TRUE];
MessageWindow.Blink[];
err ← TRUE;
CONTINUE
};
IO.EndOfStream => {
MessageWindow.Append["Parameter absent", TRUE];
MessageWindow.Blink[];
err ← TRUE;
CONTINUE
}];
};
ToggleHisto: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
IF state.histo=NIL THEN {
MessageWindow.Append["No histogram has been calculated yet", TRUE];
MessageWindow.Blink[];
Buttons.SetDisplayStyle[state.histSourceBut, $BlackOnWhite];
RETURN [];
};
state.histoOn ← ~state.histoOn;
Buttons.SetDisplayStyle[state.histSourceBut, $WhiteOnBlack];
IF state.histoOn THEN {
Buttons.ReLabel[state.showHistBut, "On"];
TRCViewer.SetHistogram[state.trcViewer, state.histo];
}
ELSE {
Buttons.ReLabel[state.showHistBut, "Off"];
TRCViewer.SetHistogram[state.trcViewer, NIL];
};
};
ReadTRC: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
SetOutput: TRCViewer.EnumerateProc ~ {
xIndex: NAT ← Real.RoundC[x];
IF ~trc[xIndex].pinned THEN
trc[xIndex].out ← Real.RoundC[y];
};
state: State ← NARROW[clientData];
trc: Hist.TRCVec;
bomb: BOOLEANFALSE;
pinned: ARRAY [0..255] OF BOOLEANALL[FALSE];
fileList: LIST OF Rope.ROPE;
dotIndex: INTEGER;
in:IO.STREAM;
modeRope: Rope.ROPE;
prev: NAT ← 0;
fileName: Rope.ROPE ← ViewerTools.GetContents[state.trcFileTypeIn];
IF fileName=NIL OR Rope.Length[fileName]=0 THEN {
MessageWindow.Append["Enter a TRC filename in TRC field please", TRUE];
MessageWindow.Blink[];
RETURN []
};
dotIndexRope.Find[fileName, ".", 0, FALSE];
IF dotIndex<0 THEN
fileList ← UPOps.Expand["%g.%k|TRCExtensions|trc|", IO.rope[fileName]]
ELSE
fileList ← LIST[fileName];
IF ~SetWDir[state] THEN RETURN [];
DO {
success:BOOLEANTRUE;
IF fileList = NIL THEN {
MessageWindow.Append["Couldn't find specified TRC input file", TRUE];
MessageWindow.Blink[];
RETURN [];
};
in FS.StreamOpen[fileName: fileList.first ! FS.Error => {
success ← FALSE;
CONTINUE
}];
IF success THEN EXIT;
fileList ← fileList.rest
};
ENDLOOP;
-- read the file in
trc ← NEW[Hist.TRCVecRec];
modeRope ← in.GetID[ !
IO.Error => {
MessageWindow.Append["TRC format error - Couldn't find interpolation mode flag", TRUE];
MessageWindow.Blink[];
bomb ← TRUE;
CONTINUE;
}
];
IF bomb THEN RETURN [];
SELECT TRUE FROM
Rope.Equal[modeRope, LogFlag, FALSE] => {
state.connectMode ← log;
Buttons.SetDisplayStyle[state.linBut, $BlackOnWhite];
Buttons.SetDisplayStyle[state.logBut, $WhiteOnBlack];
};
Rope.Equal[modeRope, LinFlag, FALSE] => {
state.connectMode ← linear;
Buttons.SetDisplayStyle[state.linBut, $WhiteOnBlack];
Buttons.SetDisplayStyle[state.logBut, $BlackOnWhite];
};
ENDCASE => {
MessageWindow.Append["TRC format error - Invalid interpolation mode flag", TRUE];
MessageWindow.Blink[];
RETURN [];
};
FOR i:CARDINAL IN [0..255] DO
c: CHAR;
index:CARDINAL;
prev ← index;
index ← IO.GetCard[in !
IO.EndOfStream => {
bomb ← TRUE; CONTINUE;
};
IO.Error => {
bomb ← TRUE;
MessageWindow.Append[IO.PutFR["TRC format error following vertex %g", IO.card[prev]], TRUE];
MessageWindow.Blink[];
CONTINUE;
}];
prev ← index;
IF bomb THEN EXIT;
trc[index].out ← IO.GetCard[in !
IO.EndOfStream => {
bomb ← TRUE;
MessageWindow.Append["TRC format error - Unexpected EOF", TRUE];
MessageWindow.Blink[];
CONTINUE;
};
IO.Error => {
bomb ← TRUE;
MessageWindow.Append[IO.PutFR["TRC format error at vertex %g", IO.card[index]], TRUE];
MessageWindow.Blink[];
CONTINUE;
}];
IF bomb THEN EXIT;
trc[index].pinned ← TRUE;
c ← in.GetChar[ !
IO.EndOfStream => {bomb ← TRUE; CONTINUE}];
IF bomb THEN EXIT;
WHILE (c # IO.CR) DO
SELECT c FROM
'* => {
pinned[index] ← TRUE;
EXIT;
};
IO.BS, IO.TAB, IO.LF, IO.FF, IO.NUL,
IO.SP, IO.DEL, IO.ESC, IO.ControlX, IO.BEL, IO.ControlA => NULL;
ENDCASE => {
bomb ← TRUE;
MessageWindow.Append[IO.PutFR["TRC format error following vertex %g '*' or CR expected", IO.card[prev]], TRUE];
MessageWindow.Blink[];
EXIT;
};
c ← in.GetChar[ !
IO.EndOfStream => {bomb ← TRUE; CONTINUE}];
IF bomb THEN EXIT;
ENDLOOP;
IF bomb THEN EXIT;
ENDLOOP;
in.Close[];
TRCViewer.Set[state.trcViewer, trc, FALSE];
TRCViewer.Enumerate[state.trcViewer, SetOutput, 0, 255];
FOR i: NAT IN [0..255] DO
trc[i].pinned ← pinned[i]
ENDLOOP;
TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; -- just a refresh really
TRCViewer.SetTitle[state.trcViewer, fileList.first];
};
SaveTRC: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
PrintOutput: TRCViewer.EnumerateProc ~ {
xIndex: NAT ← Real.RoundC[x];
out.PutF["%g %g", IO.card[xIndex], IO.card[trc[xIndex].out]];
IF trc[xIndex].pinned THEN out.PutChar['*];
out.PutChar['\n];
};
state: State ← NARROW[clientData];
trc: Hist.TRCVec;
bomb: BOOLEANFALSE;
fileList: LIST OF Rope.ROPE;
dotIndex: INTEGER;
out: IO.STREAM;
fileName: Rope.ROPE ← ViewerTools.GetContents[state.trcFileTypeIn];
IF fileName=NIL OR Rope.Length[fileName]=0 THEN {
MessageWindow.Append["Enter a TRC filename in TRC field please", TRUE];
MessageWindow.Blink[];
RETURN []
};
dotIndexRope.Find[fileName, ".", 0, FALSE];
IF dotIndex<0 THEN
fileList ← UPOps.Expand["%g.%k|TRCExtensions|trc|", IO.rope[fileName]]
ELSE
fileList ← LIST[fileName];
IF ~SetWDir[state] THEN RETURN [];
out FS.StreamOpen[fileName: fileList.first, accessOptions:create ! FS.Error => {
bomb ← TRUE;
CONTINUE
}];
IF bomb THEN {
MessageWindow.Append["Could not create specified TRC file", TRUE];
MessageWindow.Blink[];
RETURN []
};
out.PutF["-- %g \n", IO.rope[fileList.first]];
SELECT state.connectMode FROM
log => out.PutF["Log\n"];
linear => out.PutF["Linear\n"];
ENDCASE => ERROR;
trc ← TRCViewer.Get[state.trcViewer];
TRCViewer.Enumerate[state.trcViewer, PrintOutput, 0, 255];
out.Close[];
};
SetWDir: PROC [state: State] RETURNS [ok:BOOLEANTRUE] ~ {
dirName: Rope.ROPE ← ViewerTools.GetContents[state.wdTypeIn];
IF dirName=NIL OR Rope.Length[dirName]=0 THEN {
dirName ← FS.GetDefaultWDir[];
MessageWindow.Append[IO.PutFR["Assuming working directory %g", IO.rope[dirName]], TRUE];
MessageWindow.Blink[];
RETURN []
};
FS.SetDefaultWDir[dirName !
FS.Error => {
MessageWindow.Append[IO.PutFR["Funny working directory name: %g", IO.rope[dirName]], TRUE];
MessageWindow.Blink[];
ok ← FALSE;
CONTINUE;
}];
};
CalcHisto: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
fileList: LIST OF Rope.ROPE;
dotIndex: INTEGER;
min, max:NAT;
err:BOOLEANFALSE;
fileName: Rope.ROPE ← ViewerTools.GetContents[state.histSourceTypeIn];
IF fileName=NIL OR Rope.Length[fileName]=0 THEN {
MessageWindow.Append["Enter an AIS filename in Hist field please", TRUE];
MessageWindow.Blink[];
RETURN []
};
dotIndexRope.Find[fileName, ".", 0, FALSE];
IF dotIndex<0 THEN
fileList ← UPOps.Expand["%g.%k|AISExtensions|AIS|", IO.rope[fileName]]
ELSE
fileList ← LIST[fileName];
IF ~SetWDir[state] THEN RETURN [];
[min, err] ← GetCardFromViewer[state.blackTypeIn];
IF err OR min NOT IN [0..255] THEN {
MessageWindow.Append["Invalid value for histogram black value [0..255]", TRUE];
MessageWindow.Blink[];
RETURN []
};
[max, err] ← GetCardFromViewer[state.whiteTypeIn];
IF err OR max NOT IN [0..255] THEN {
MessageWindow.Append["Invalid value for histogram white value [0..255]", TRUE];
MessageWindow.Blink[];
RETURN []
};
DO {
success:BOOLEANTRUE;
IF fileList = NIL THEN {
MessageWindow.Append["Couldn't find specified input file", TRUE];
MessageWindow.Blink[];
state.histo ← NIL;
state.histoOn ← FALSE;
Buttons.SetDisplayStyle[state.histSourceBut, $BlackOnWhite];
Buttons.ReLabel[state.showHistBut, "Off"];
TRCViewer.SetHistogram[state.trcViewer, NIL];
RETURN [];
};
state.histo ← Hist.Calc[fileList.first, min, max ! FS.Error => {
success ← FALSE;
CONTINUE
}];
IF success THEN EXIT;
fileList ← fileList.rest
};
ENDLOOP;
Buttons.SetDisplayStyle[state.histSourceBut, $WhiteOnBlack];
state.histoOn ← TRUE;
Buttons.ReLabel[state.showHistBut, "On"];
TRCViewer.SetHistogram[state.trcViewer, state.histo];
};
Equalise: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
trc: Hist.TRCVec;
IF state.histo=NIL THEN {
MessageWindow.Append["No histogram has been calculated yet", TRUE];
MessageWindow.Blink[];
RETURN []
};
trc ← Hist.Equalize[state.histo];
trc[0].pinned ← trc[255].pinned ← TRUE;
TRCViewer.Set[state.trcViewer, trc];
};
SelGamma: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
ViewerTools.SetSelection[NARROW[clientData, State].gammaTypeIn];
UpdateColorMap[state];
};
SelBlack: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
ViewerTools.SetSelection[NARROW[clientData, State].blackTypeIn];
};
SelWhite: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
ViewerTools.SetSelection[NARROW[clientData, State].whiteTypeIn];
};
Shift: ENTRY Buttons.ButtonProc = {
state: State ← NARROW[clientData];
newVertices: Hist.TRCVec ← NEW[Hist.TRCVecRec];
oldVertices: Hist.TRCVec ← TRCViewer.Get[state.trcViewer];
delta: NAT ← 1;
dir: INT ← 1;
IF shift THEN delta ← delta * 16;
IF control THEN delta ← delta * 4;
IF mouseButton=blue THEN dir ← -1;
FOR i: NAT IN [0..Hist.MaxPixel] DO
p:INT ← i+(delta*dir);
SELECT TRUE FROM
p<0 => { newVertices[i].out ← oldVertices[0].out};
p>255 => { newVertices[i].out ← oldVertices[255].out};
ENDCASE => newVertices[i] ← oldVertices[p];
ENDLOOP;
IF state.addVertexOnShiftOrRotate THEN
newVertices[0].pinned ← newVertices[255].pinned ← TRUE;
TRCViewer.Set[state.trcViewer, newVertices];
};
Rotate: ENTRY Buttons.ButtonProc = {
state: State ← NARROW[clientData];
newVertices: Hist.TRCVec ← NEW[Hist.TRCVecRec];
oldVertices: Hist.TRCVec ← TRCViewer.Get[state.trcViewer];
delta: NAT ← 1;
dir: INT ← 1;
IF shift THEN delta ← delta * 16;
IF control THEN delta ← delta * 4;
IF mouseButton=blue THEN dir ← -1;
FOR i: NAT IN [0..Hist.MaxPixel] DO
p:INT ← i+(delta*dir);
newVertices[i] ← oldVertices[(256+p) MOD 256];
ENDLOOP;
IF state.addVertexOnShiftOrRotate THEN
newVertices[0].pinned ← newVertices[255].pinned ← TRUE;
TRCViewer.Set[state.trcViewer, newVertices];
};
SelectWD: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
ViewerTools.SetSelection[NARROW[clientData, State].wdTypeIn];
};
SelectTRC: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
ViewerTools.SetSelection[NARROW[clientData, State].trcFileTypeIn];
};
SelectHist: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
ViewerTools.SetSelection[NARROW[clientData, State].histSourceTypeIn];
};
SelectInScale: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
d: REAL; err: BOOLEAN;
[d, err] ← GetDensityFromScaleViewer[state.inputScaleTypeIn, state.inputMode];
IF ~err THEN {
state.maxInputDens ← d;
TRCViewer.SetMaxDensityIn[state.trcViewer, d];
};
IF mouseButton=red OR mouseButton=blue THEN {
SELECT state.inputMode FROM
density => {
state.inputMode ← reflectance;
Buttons.ReLabel[state.setInputModeBut, "MinRIn"];
ViewerTools.SetContents[state.inputScaleTypeIn, IO.PutFR["%g", IO.real[TRCViewer.DensToRef[state.maxInputDens]]]];
};
ENDCASE => {
state.inputMode ← density;
Buttons.ReLabel[state.setInputModeBut, "MaxDIn"];
ViewerTools.SetContents[state.inputScaleTypeIn, IO.PutFR["%g", IO.real[state.maxInputDens]]];
};
TRCViewer.SetFeedBackModes[state.trcViewer, state.inputMode, state.outputMode];
};
ViewerTools.SetSelection[state.inputScaleTypeIn];
};
SelectOutScale: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
d: REAL; err: BOOLEAN;
[d, err] ← GetDensityFromScaleViewer[state.outputScaleTypeIn, state.outputMode];
IF ~err THEN {
state.maxOutputDens ← d;
TRCViewer.SetMaxDensityOut[state.trcViewer, d];
};
IF mouseButton=red OR mouseButton=blue THEN {
SELECT state.outputMode FROM
density => {
state.outputMode ← reflectance;
Buttons.ReLabel[state.setOutputModeBut, "MinROut"];
ViewerTools.SetContents[state.outputScaleTypeIn, IO.PutFR["%g", IO.real[TRCViewer.DensToRef[state.maxOutputDens]]]];
};
ENDCASE => {
state.outputMode ← density;
Buttons.ReLabel[state.setOutputModeBut, "MaxDOut"];
ViewerTools.SetContents[state.outputScaleTypeIn, IO.PutFR["%g", IO.real[state.maxOutputDens]]];
};
TRCViewer.SetFeedBackModes[state.trcViewer, state.inputMode, state.outputMode];
};
ViewerTools.SetSelection[state.outputScaleTypeIn];
TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; -- just a refresh really
};
SetLinearMode: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
state.connectMode ← linear;
Buttons.SetDisplayStyle[state.linBut, $WhiteOnBlack];
Buttons.SetDisplayStyle[state.logBut, $BlackOnWhite];
TRCViewer.SetConnectMode[state.trcViewer, state.connectMode];
};
SetLogMode: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
state.connectMode ← log;
Buttons.SetDisplayStyle[state.linBut, $BlackOnWhite];
Buttons.SetDisplayStyle[state.logBut, $WhiteOnBlack];
TRCViewer.SetConnectMode[state.trcViewer, state.connectMode];
};
InitTRC: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
SetOutput: TRCViewer.EnumerateProc ~ {
trc[Real.RoundC[x]].out ← Real.RoundC[y];
};
state: State ← NARROW[clientData];
trc: Hist.TRCVec ← NEW[Hist.TRCVecRec];
trc[0].pinned ← trc[255].pinned ← TRUE;
trc[0].out ← 0; trc[255].out ← 255;
TRCViewer.Set[state.trcViewer, trc, FALSE];
TRCViewer.Enumerate[state.trcViewer, SetOutput, 0, 255];
TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; -- just a refresh really
};
Negate: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY ← NIL, mouseButton: Menus.MouseButton ← red, shift: BOOL ← FALSE, control: BOOL ← FALSE] -- = {
state: State ← NARROW[clientData];
trc: Hist.TRCVec ← TRCViewer.Get[state.trcViewer];
FOR i: NAT IN [0..Hist.MaxPixel] DO
trc[i].out ← 255 - trc[i].out;
ENDLOOP;
TRCViewer.Set[state.trcViewer, trc];
};
Register: PROC ~ {
Commander.Register[key:"BuildTRC", proc:StartNewInstance];
};
Register[];
END.