CtToolCommandsImpl.mesa
Copyright Ó 1985, 1988, 1992 by Xerox Corporation. All rights reserved.
Glassner, October 27, 1988 5:45:26 pm PDT
Bloomenthal, July 3, 1992 1:28 pm PDT
DIRECTORY Args, Buttons, Commander, Controls, Convert, CtBasic, CtDispatch, CtMap, CtMisc, CommanderOps, FileNames, FS, G2dBasic, Icons, Imager, IO, ImagerSample, MessageWindow, Real, RealFns, Rope, TEditSelection, TiogaMenuOps, ViewerClasses, ViewerOps, ViewerTools;
CtToolCommandsImpl: CEDAR PROGRAM
IMPORTS Args, Buttons, Controls, Convert, CtBasic, CtDispatch, CtMap, CtMisc, FileNames, FS, Icons, ImagerSample, Imager, IO, MessageWindow, Real, RealFns, Rope, TEditSelection, TiogaMenuOps, ViewerOps, ViewerTools
~ BEGIN
Imported Types
CommandProc:  TYPE ~ Commander.CommandProc;
ButtonList:   TYPE ~ Controls.ButtonList;
IntegerPair:   TYPE ~ CtBasic.IntegerPair;
PixelArray:   TYPE ~ CtBasic.PixelArray;
RGB:     TYPE ~ CtBasic.RGB;
SampleMaps:   TYPE ~ CtBasic.SampleMaps;
Cmap:     TYPE ~ CtMap.Cmap;
Comp:     TYPE ~ CtMap.Comp;
Mouse:    TYPE ~ CtMisc.Mouse;
SampleMap:   TYPE ~ ImagerSample.SampleMap;
SampleBuffer:  TYPE ~ ImagerSample.SampleBuffer;
ROPE:     TYPE ~ Rope.ROPE;
Viewer:    TYPE ~ ViewerClasses.Viewer;
Globals
awakeWord:   ROPE ~ "AWAKE ";
asleepWord:   ROPE ~ "ASLEEP";
pixelBName:   ROPE ~ "Pixel:";       -- name of pixel button
mapredBName:  ROPE ~ "mR:";       -- name of red cmap button
mapgrnBName:  ROPE ~ "mG:";       -- name of green cmap button
mapbluBName:  ROPE ~ "mB:";       -- name of blue cmap button
zoomBName:   ROPE ~ "Zoom:";       -- name of zoom button
8-bit buttons
rawBName:  ROPE ~ "Gray:";       -- name of raw pixel value button
24-bit buttons
redBName:  ROPE ~ "bR:";       -- name of red button
grnBName:  ROPE ~ "bG:";       -- name of green button
bluBName:  ROPE ~ "bB:";       -- name of blue button
fixed:     Imager.Font ~ Imager.FindFontScaled["xerox/pressfonts/Gacha-mrr", 12.0];
boldFixed:   Imager.Font ~ Imager.FindFontScaled["xerox/pressfonts/Gacha-brr", 12.0];
arrow:     Imager.Font ~ Imager.FindFontScaled["xerox/pressfonts/Arrows-mrr", 12.0];
Local Types
Tool:      TYPE ~ REF ToolRep;
ToolRep:    TYPE ~ RECORD [
viewer info
outer:      Viewer ¬ NIL,     -- parent viewer
outerData:    Controls.OuterData ¬ NIL,  -- parent viewer
zooming and panning control
zoomFactor:    NAT ¬ 1,       -- current replication
sUL:      IntegerPair ¬ [],     -- screen co-ords of UL pixel
pUL:      IntegerPair ¬ [],     -- pixel co-ords of the UL pixel
center:     IntegerPair ¬ [],     -- center of color display
buttons and state
poi:      IntegerPair ¬ [],     -- point of (current) interest
raw:      INTEGER ¬ 0,     -- current rawscale value (8bpp)
rawrgb:     RGB ¬ [0, 0, 0],     -- current rgb value (24bpp)
maprgb:     RGB ¬ [0, 0, 0],     -- colormap entries for poi
awake:     BOOL ¬ TRUE,     -- on/off conditional
frame buffer contents
maps:      SampleMaps ¬ NIL,    -- color display sample maps
rMap, gMap:    SampleMap ¬ NIL,    -- 8 bit red and green maps (copy)
paR, paG, paB:   PixelArray ¬ NIL,    -- working image
opaR, opaG, opaB:  PixelArray ¬ NIL,    -- original image
colorMap:     Cmap ¬ NIL,      -- color display colormap
cursors
cursorLooks:    CursorLooks ¬ onesAreBlack -- how to show the cursor
];
Image Tool Commands
ToolCmd: CommandProc ~ {
GetFBContents: PROC ~ {
IO.PutRope[cmd.out, "Getting memory - please wait a moment..."];
d.maps ¬ CtBasic.GetColorDisplayMaps[];
SELECT d.maps.bpp FROM
8 => {
d.paR ¬ CtBasic.PixelArrayFromSampleMap[d.maps[0].map];
d.opaR ¬ CtBasic.PixelArrayFromSampleMap[d.maps[0].map];
};
24 => {
[d.rMap, d.gMap] ¬ CtBasic.RedAndGrnFromRG[d.maps[0].map];
d.paR ¬ CtBasic.PixelArrayFromSampleMap[d.rMap];
d.paG ¬ CtBasic.PixelArrayFromSampleMap[d.gMap];
d.paB ¬ CtBasic.PixelArrayFromSampleMap[d.maps[1].map];
d.opaR ¬ CtBasic.PixelArrayFromSampleMap[d.rMap];
d.opaG ¬ CtBasic.PixelArrayFromSampleMap[d.gMap];
d.opaB ¬ CtBasic.PixelArrayFromSampleMap[d.maps[1].map];
};
ENDCASE;
d.colorMap ¬ CtMap.Read[];
IO.PutRope[cmd.out, "Ready!\n"];
};
d: Tool ¬ NEW[ToolRep];
grayButtons: ButtonList ¬ LIST[
Controls.TextButton[name: rawBName, text: "0 ", clientData: d, row: 2, proc: TBProc]
];
rgbButtons: ButtonList ¬ LIST[
Controls.TextButton[name: redBName, text: "0 ", clientData: d, row: 2, proc: TBProc],
Controls.TextButton[name: grnBName, text: "0 ", clientData: d, row: 2, proc: TBProc],
Controls.TextButton[name: bluBName, text: "0 ", clientData: d, row: 2, proc: TBProc]
];
buttons: ButtonList ¬ LIST[
Controls.ClickButton[name: " ", row: 3, clientData: d, font: boldFixed],
Controls.ClickButton[name: " L ", row: 3, clientData: d, font: boldFixed],
Controls.ClickButton[name: " M ", row: 3, clientData: d, font: boldFixed],
Controls.ClickButton[name: " R ", row: 3, clientData: d, font: boldFixed],
Controls.ClickButton[name: "P", row: 2, clientData: d, font: boldFixed],
Controls.ClickButton[name: "z*2", proc: ZoomTimes2, row: 2, clientData: d, font: fixed],
Controls.ClickButton[name: " ? ", proc: Show, row: 2, clientData: d, font: fixed],
Controls.ClickButton[name: "z/2", proc: ZoomOver2, row: 2, clientData: d, font: fixed],
Controls.ClickButton[name: "S", row: 1, clientData: d, font: boldFixed],
Controls.ClickButton[name: "z+1", proc: ZoomPlus1, row: 1, clientData: d, font: fixed],
Controls.ClickButton[name: "?+c", proc: ShowCenter, row: 1, clientData: d, font: fixed],
Controls.ClickButton[name: "z-1", proc: ZoomMinus1, row: 1, clientData: d, font: fixed],
Controls.ClickButton[name: "C", clientData: d, font: boldFixed],
Controls.ClickButton[name: "z*8", proc: ZoomTimes8, clientData: d, font: fixed],
Controls.ClickButton[name: " ", clientData: d, font: fixed],
Controls.ClickButton[name: "z/8", proc: ZoomOver8, clientData: d, font: fixed],
Controls.ClickButton[name: " ", row: 3, clientData: d, font: fixed],
Controls.ClickButton[name: " ", row: 2, clientData: d, font: fixed],
Controls.ClickButton[name: " ", row: 1, clientData: d, font: fixed],
Controls.ClickButton[name: " ", row: 0, clientData: d, font: fixed],
Controls.ClickButton[name: "x", proc: Left, row: 3, clientData: d, font: arrow, h: 15],
Controls.ClickButton[name: "n", proc: Right, row: 2, clientData: d, font: arrow, h: 15],
Controls.ClickButton[name: ",", proc: Up, row: 1, clientData: d, font: arrow, h: 15],
Controls.ClickButton[name: "v", proc: Down, row: 0, clientData: d, font: arrow, h: 15],
Controls.TextButton[name: pixelBName, text: "0 0 ", proc: TBProc, clientData: d, row: 3],
Controls.TextButton[name: zoomBName, text: "1 ", proc: TBProc, clientData: d, row: 3],
Controls.ClickButton[name: "buf:", row: 2, clientData: d, font: fixed],
Controls.ClickButton[name: "map:", row: 1, clientData: d, font: fixed],
Controls.TextButton[name: mapredBName, text: "0 ", clientData: d, row: 1, proc: TBProc],
Controls.TextButton[name: mapgrnBName, text: "0 ", clientData: d, row: 1, proc: TBProc],
Controls.TextButton[name: mapbluBName, text: "0 ", clientData: d, row: 1, proc: TBProc],
Controls.ClickButton[name: awakeWord, proc: Awake, clientData: d, row: 0],
Controls.ClickButton[name: "InvertCursor", proc: InvertCursor, clientData: d, row: 0],
Controls.ClickButton[name: "Redraw", proc: Redraw, clientData: d, guarded: TRUE, row: 0],
Controls.ClickButton[name: "Reset", proc: Reset, clientData: d, guarded: TRUE, row: 0],
Controls.ClickButton[name: " ", row: 3, clientData: d],
Controls.ClickButton[name: "Help", row: 3, clientData: d, proc: HelpProc]
];
[] ← Terminal.ModifyColorFrame[Terminal.Current[], GetFBContents];
d.center ¬ [(d.paR.x+d.paR.w/2)-1, (d.paR.y+d.paR.h/2)-1];
d.poi ¬ AddIntegerPairs[d.center, [1, 0]];
Now build the composite button list
FOR l: ButtonList ¬ buttons, l.rest DO -- presumes buttons # NIL
IF l.rest # NIL THEN LOOP;
l.rest ¬ IF d.maps.bpp = 8 THEN grayButtons ELSE rgbButtons;
EXIT;
ENDLOOP;
d.outerData ¬ Controls.OuterViewer[
name: "CtTool",
column: right,
buttons: buttons,
typescriptHeight: --one line = 18-- 108,
destroyProc: Destroy,
clientData: d,
noOpen: TRUE];
d.outer ¬ d.outerData.parent;
d.outer.icon ¬ IF d.maps.bpp = 8 THEN icon8bits ELSE icon24bits;
UpdateButtons[d];
ViewerOps.OpenIcon[d.outer];
CtMisc.RegisterWatch[[d, ToolMouse, ToolChange]];
};
Menu Button Response Procedures
Text Button Response Procedures
TBProc: Controls.ClickProc ~ {  -- called if user types any text box and CR
d: Tool ¬ NARROW[clientData];
ReadButtonsAndRespond[d];
};
Move/Zoom Button Response Procedures
DoMove: PROC [clientData: REF, move: IntegerPair] ~ {
d: Tool ¬ NARROW[clientData];
d.poi ¬ AddIntegerPairs[d.poi, move];
SetTextIntegerPair[d, pixelBName, d.poi];
ReadButtonsAndRespond[d];
PrintPixel[d];
};
DoZoom: PROC [d: Tool, scale, offset: REAL] ~ {
factor: INTEGER ¬ Real.InlineRoundI[d.zoomFactor*scale+offset];
SetTextInt[d, zoomBName, MAX[1, factor]]; 
ReadButtonsAndRespond[d];
};
Left:    Controls.ClickProc ~ {DoMove[clientData, [-1, 0]]};
Right:   Controls.ClickProc ~ {DoMove[clientData, [ 1, 0]]};
Up:    Controls.ClickProc ~ {DoMove[clientData, [ 0, -1]]};
Down:   Controls.ClickProc ~ {DoMove[clientData, [ 0, 1]]};
ZoomPlus1:  Controls.ClickProc ~ {DoZoom[NARROW[clientData], 1.0,  1.0]};
ZoomMinus1: Controls.ClickProc ~ {DoZoom[NARROW[clientData], 1.0,  -1.0]};
ZoomTimes2: Controls.ClickProc ~ {DoZoom[NARROW[clientData], 2.0,  0.0]};
ZoomOver2:  Controls.ClickProc ~ {DoZoom[NARROW[clientData], 1.0/2.0, 0.0]};
ZoomTimes8: Controls.ClickProc ~ {DoZoom[NARROW[clientData], 8.0,  0.0]};
ZoomOver8:  Controls.ClickProc ~ {DoZoom[NARROW[clientData], 1.0/8.0, 0.0]};
Toggle Button Response Procedures
Awake: Buttons.ButtonProc ~ {
d: Tool ¬ NARROW[clientData];
Buttons.ReLabel[parent, IF d.awake ¬ NOT d.awake THEN awakeWord ELSE asleepWord];
Buttons.SetDisplayStyle[parent, IF d.awake THEN $BlackOnWhite ELSE $WhiteOnBlack];
IF d.awake
THEN CtMisc.RegisterWatch[[d, ToolMouse, ToolChange]]
ELSE CtMisc.UnRegisterWatch[[d, ToolMouse, ToolChange]];
};
InvertCursor: Buttons.ButtonProc ~ {
d: Tool ¬ NARROW[clientData];
d.cursorLooks ¬ IF d.cursorLooks = onesAreWhite THEN onesAreBlack ELSE onesAreWhite;
Buttons.SetDisplayStyle[parent, IF d.cursorLooks = onesAreWhite THEN $WhiteOnBlack ELSE $BlackOnWhite];
[] ← Terminal.SetColorCursorPresentation[Terminal.Current[], d.cursorLooks]
};
Command Response Procedures
Reset: Buttons.ButtonProc ~ {
d: Tool ¬ NARROW[clientData];
d.poi ¬ AddIntegerPairs[d.center, [1, 0]];
d.sUL ¬ d.pUL ¬ [0, 0];
d.zoomFactor ¬ 1;
d.paR ¬ d.opaR;
IF d.maps.bpp = 24 THEN { d.paG ¬ d.opaG; d.paB ¬ d.opaB; };
CtMap.Write[d.colorMap];
UpdateButtons[d];
DoRedraw[d];
};
Redraw: Buttons.ButtonProc ~ {
d: Tool ¬ NARROW[clientData];
DoRedraw[d];
};
Display Button Response Procedures
Show: Controls.ClickProc ~ {
d: Tool ¬ NARROW[clientData];
ReadButtonsAndRespond[d];
PrintPixel[d];
};
ShowCenter: Controls.ClickProc ~ {
d: Tool ¬ NARROW[clientData];
SetTextIntegerPair[d, pixelBName, d.poi];
PrintPixel[d];
DoRedraw[d];  -- don't check poi against pixel, because we just made them the same!
};
Text Button Update
GetTextInt: PROC [d: Tool, buttonName: ROPE] RETURNS [value: INTEGER ¬ 0] ~ {
textV: Viewer ¬ Controls.ButtonFind[d.outerData, buttonName].textViewer;
contents: ROPE ¬ ViewerTools.GetContents[textV];
IF Rope.IsEmpty[contents] THEN value ¬ 0
ELSE value ¬ Convert.IntFromRope[contents ! Convert.Error => {value ¬ -1; CONTINUE;};];
};
SetTextRope: PROC [d: Tool, buttonName, text: ROPE] ~ {
textV: Viewer ¬ Controls.ButtonFind[d.outerData, buttonName].textViewer;
ViewerTools.SetContents[textV, text];
};
SetTextInt: PROC [d: Tool, buttonName: ROPE, value: INTEGER] ~ {
textV: Viewer ¬ Controls.ButtonFind[d.outerData, buttonName].textViewer;
ViewerTools.SetContents[textV, IO.PutFR["%3g", IO.int[value]]];
};
SetTextIntegerPair: PROC [d: Tool, buttonName: ROPE, p: IntegerPair] ~ {
textV: Viewer ¬ Controls.ButtonFind[d.outerData, buttonName].textViewer;
ViewerTools.SetContents[textV, IO.PutFR["%3g %3g", IO.int[p.x], IO.int[p.y]]];
};
UpdateButtons: PROC [d: Tool] ~ {
IF PoiInImage[d]
THEN {
IF d.maps.bpp = 8
THEN {
d.maprgb ¬ CtMap.ReadEntry[d.paR[d.poi.y][d.poi.x]];
SetTextInt[d, rawBName, d.paR[d.poi.y][d.poi.x]];
}
ELSE {
d.maprgb ¬ CtMap.ReadEntry24[
d.paR[d.poi.y][d.poi.x], d.paG[d.poi.y][d.poi.x], d.paB[d.poi.y][d.poi.x]];
SetTextInt[d, redBName, d.paR[d.poi.y][d.poi.x]];
SetTextInt[d, grnBName, d.paG[d.poi.y][d.poi.x]];
SetTextInt[d, bluBName, d.paB[d.poi.y][d.poi.x]];
};
SetTextInt[d, mapredBName, d.maprgb.r];
SetTextInt[d, mapgrnBName, d.maprgb.g];
SetTextInt[d, mapbluBName, d.maprgb.b];
}
ELSE {
IF d.maps.bpp = 8
THEN {
SetTextRope[d, rawBName, "---"];
}
ELSE {
SetTextRope[d, redBName, "---"];
SetTextRope[d, grnBName, "---"];
SetTextRope[d, bluBName, "---"];
};
SetTextRope[d, mapredBName, "---"];
SetTextRope[d, mapgrnBName, "---"];
SetTextRope[d, mapbluBName, "---"];
};
SetTextInt[d, zoomBName, d.zoomFactor];
SetTextIntegerPair[d, pixelBName, d.poi];
};
ReadButtonsAndRespond: PROC [d: Tool] ~ {
changeZoom: BOOLEAN ¬ FALSE;   -- redraw the color display?
changeCmap: BOOLEAN ¬ FALSE;   -- change the color map?
changeFb: BOOLEAN ¬ FALSE;    -- change the pixel value?
changePoi: BOOLEAN ¬ FALSE;   -- change the poi?
newP, newZ: INT;
newmap, newclr: RGB;
Check poi:
a1, a2: Args.Arg;
[a1, a2] ¬ Args.ArgsGetFromRope[ViewerTools.GetContents[
Controls.ButtonFind[d.outerData, pixelBName].textViewer], "%ii"];
IF d.poi.x # a1.int OR d.poi.y # a2.int THEN {
changePoi ¬ TRUE;
d.poi ¬ [a1.int, a2.int];
};
Check zoom factor:
newZ ¬ ClipInt[GetTextInt[d, zoomBName], 0, 2048];
IF d.zoomFactor # newZ THEN {
changeZoom ¬ TRUE;
newZ ¬ ClipInt[GetTextInt[d, zoomBName], 0, 2048];
};
Check mapped red, green, and blue values:
newmap.r ¬ ClipInt[GetTextInt[d, mapredBName], 0, 255];
newmap.g ¬ ClipInt[GetTextInt[d, mapgrnBName], 0, 255];
newmap.b ¬ ClipInt[GetTextInt[d, mapbluBName], 0, 255];
IF newmap # d.maprgb THEN changeCmap ¬ TRUE;
Check color values
IF d.maps.bpp = 8
THEN {
newP ¬ ClipInt[GetTextInt[d, rawBName], 0, 255];
IF newP # d.raw THEN {
changeFb ¬ TRUE;
};
}
ELSE {
newclr.r ¬ ClipInt[GetTextInt[d, redBName], 0, 255];
newclr.g ¬ ClipInt[GetTextInt[d, grnBName], 0, 255];
newclr.b ¬ ClipInt[GetTextInt[d, bluBName], 0, 255];
IF newclr # d.rawrgb THEN changeFb ¬ TRUE;
};
IF NOT PoiInImage[d] THEN changeFb ¬ changeCmap ¬ FALSE;
And now respond to changes:
If Pixel (Poi) changes, { redraw to put Poi at center, reset buttons, return }
If Fb contents change, { set raw value in d, write into colorfb (redraw if no zoom later)}
If colormap contents change, { update color map }
If zoom changes, { set new zoom factor in d, redraw colorfb }
IF changePoi THEN {
DoRedraw[d];
UpdateButtons[d];
RETURN;
};
IF changeFb THEN {
IF d.maps.bpp = 8
THEN d.raw ¬ newP
ELSE d.rawrgb ¬ newclr;
ChangeFb[d];
IF NOT changeZoom THEN RedrawPoi[d];
};
IF changeCmap THEN {
d.maprgb ¬ newmap;
ChangeCmap[d];
};
IF changeZoom THEN { d.zoomFactor ¬ newZ; DoRedraw[d]; };
UpdateButtons[d];
};
Mouse Procedures
ToolMouse: CtMisc.MouseProc ~ {
d: Tool ¬ NARROW[clientData];
SELECT mouse.state FROM
down => {
};
held => {
};
up => {
AdjustMouse[d, mouse.pos];
SELECT mouse.button FROM
left =>
IF mouse.shiftKey
THEN DoMouseZoom[d, 1.0, 1.0]
ELSE IF mouse.controlKey
THEN DoMouseZoom[d, 8.0, 0.0]
ELSE DoMouseZoom[d, 2.0, 0.0];
middle =>
IF mouse.shiftKey AND mouse.controlKey
THEN Debug[d]
ELSE {
PrintPixel[d];
IF mouse.shiftKey THEN DoRedraw[d];
};
right =>
IF mouse.shiftKey
THEN DoMouseZoom[d, 1.0, -1.0]
ELSE IF mouse.controlKey
THEN DoMouseZoom[d, 1.0/8.0, 0.0]
ELSE DoMouseZoom[d, 1.0/2.0, 0.0];
ENDCASE;
};
ENDCASE;
};
AdjustMouse: PROC [d: Tool, poi: IntegerPair] ~ {
sets d.poi to pixel selected by mouse
d.poi.x ¬ d.pUL.x+Real.Floor[(poi.x - d.sUL.x)/Real.Float[d.zoomFactor]];
d.poi.y ¬ d.pUL.y+Real.Floor[(poi.y - d.sUL.y)/Real.Float[d.zoomFactor]];
};
DoMouseZoom: PROC [d: Tool, scale, offset: REAL] ~ {
factor: INTEGER ¬ Real.InlineRoundI[d.zoomFactor*scale+offset];
factor ¬ MAX[1, factor];
SetTextInt[d, zoomBName, factor];
SetTextIntegerPair[d, pixelBName, d.poi];
ReadButtonsAndRespond[d];
};
Typescript Reporting Procedures
PrintPixel: PROC [d: Tool] ~ {
poi: IntegerPair ¬ d.poi;
rope: ROPE;
IF PoiInImage[d]
THEN {
rgb: RGB;
IF d.maps.bpp = 8
THEN {
d.raw ¬ d.paR[d.poi.y][d.poi.x];
rgb ¬ CtMap.ReadEntry[d.raw];
rope ¬ IO.PutFR["pixel [%4g %4g] = %3g", IO.int[poi.x], IO.int[poi.y], IO.int[d.raw]];
}
ELSE {
rgb ¬ CtMap.ReadEntry24[d.paR[poi.y][poi.x], d.paG[poi.y][poi.x], d.paB[poi.y][poi.x]];
rope ¬ IO.PutFR["pixel [%4g %4g] = (%3g %3g %3g)",
IO.int[poi.x], IO.int[poi.y],
IO.int[d.paR[poi.y][poi.x]], IO.int[d.paG[poi.y][poi.x]], IO.int[d.paB[poi.y][poi.x]]];
};
Controls.TypescriptWrite[d.outerData.typescript, rope];
rope ¬ IO.PutFR[" --- map = { %3g %3g %3g }\n", IO.int[rgb.r], IO.int[rgb.g], IO.int[rgb.b]];
Controls.TypescriptWrite[d.outerData.typescript, rope];
}
ELSE {
Controls.TypescriptWrite[d.outerData.typescript,
IO.PutFR["no image at pixel [%4g %4g]\n", IO.int[poi.x], IO.int[poi.y]]];
};
UpdateButtons[d];
};
ReportMessage: PROC [d: Tool, msg: ROPE] ~ {
Controls.TypescriptWrite[d.outerData.typescript, msg];
};
Redraw Color Display Procedures
ToolChange: CtMisc.ChangeProc ~ {
d: Tool ¬ NARROW[clientData];
awakeb: Viewer ¬ Controls.ButtonFind[d.outerData, awakeWord].textViewer;
IF awakeb = NIL THEN awakeb ¬ Controls.ButtonFind[d.outerData, asleepWord].textViewer;
Buttons.SetDisplayStyle[awakeb, $WhiteOnBlack];
CtMisc.UnRegisterWatch[[d, ToolMouse, ToolChange]];
ViewerOps.CloseViewer[d.outer];
MessageWindow.Append[" CtTool: color display changed; restart me!"];
MessageWindow.Blink[];
};
RedrawPoi: PROC [d: Tool] ~ {
We should just update the affected region of the fb; redrawing the screen is overkill
DoRedraw[d];
};
ChangeFb: PROC [d: Tool] ~ {
IF NOT PoiInImage[d] THEN RETURN;
IF d.maps.bpp = 8
THEN {
d.paR[d.poi.y][d.poi.x] ¬ d.raw;
}
ELSE {
d.paR[d.poi.y][d.poi.x] ¬ d.rawrgb.r;
d.paG[d.poi.y][d.poi.x] ¬ d.rawrgb.g;
d.paB[d.poi.y][d.poi.x] ¬ d.rawrgb.b;
};
};
ChangeCmap: PROC [d: Tool] ~ {
IF d.maps.bpp = 8
THEN CtMap.WriteEntry[d.raw, d.maprgb]
ELSE CtMap.WriteEntry24[d.rawrgb.r, d.rawrgb.g, d.rawrgb.b, d.maprgb];
};
DoRedraw: PROC [d: Tool] ~ {
Action: PROC ~ {
InnerOneMap: PROC[map: SampleMap, pa: PixelArray] ~ {
xReps, yReps: NAT;
leftPixel, thisPixel: IntegerPair ¬ d.pUL;
paY: SampleBuffer;
scanLine: ImagerSample.SampleBuffer ¬ ImagerSample.ObtainScratchSamples[d.paR.x+d.paR.w];
build first set of blocks
IF thisPixel.y >= 0 AND thisPixel.y < pa.h
THEN {
paY ¬ pa[thisPixel.y];
xReps ¬ rUL.x;
FOR x: NAT IN [pa.x..pa.x+pa.w) DO
IF thisPixel.x >= 0 AND thisPixel.x < pa.w
THEN scanLine[x] ¬ paY[thisPixel.x]
ELSE scanLine[x] ¬ 0;
xReps ¬ xReps - 1;
IF xReps = 0 THEN {
thisPixel.x ¬ thisPixel.x+1;
xReps ¬ zoom;
};
ENDLOOP;
}
ELSE FOR x: NAT IN [pa.x..pa.x+pa.w) DO scanLine[x] ¬ 0; ENDLOOP;
yReps ¬ 1+rUL.y;
FOR y: NAT IN [pa.y..pa.y+pa.h) DO
yReps ¬ yReps - 1;
IF yReps = 0 THEN {
leftPixel.y ¬ leftPixel.y+1;
yReps ¬ zoom;
IF leftPixel.y >= 0 AND leftPixel.y < pa.h
THEN {
paY ¬ pa[leftPixel.y];
thisPixel ¬ leftPixel;
xReps ¬ 1+rUL.x;
FOR x: NAT IN [pa.x..pa.x+pa.w) DO
IF thisPixel.x >= 0 AND thisPixel.x < pa.w
THEN scanLine[x] ¬ paY[thisPixel.x]
ELSE scanLine[x] ¬ 0;
xReps ¬ xReps-1;
IF xReps = 0 THEN {
xReps ¬ zoom;
thisPixel.x ¬ thisPixel.x+1;
};
ENDLOOP;
}
ELSE FOR x: NAT IN [pa.x..pa.x+pa.w) DO scanLine[x] ¬ 0; ENDLOOP;
};
ImagerSample.PutSamples[map, [y, 0],, scanLine, 0, pa.w];
ENDLOOP;
ImagerSample.ReleaseScratchSamples[scanLine];
};
InnerThreeMaps: PROC [rgdstmap, bdstmap: SampleMap,
redpa, grnpa, blupa: PixelArray] ~ {
xReps, yReps: NAT;
leftPixel, thisPixel: IntegerPair ¬ d.pUL;
redpaY, grnpaY, blupaY: SampleBuffer;
rgdstmap2: SampleMap ¬ CtBasic.GetRedGrn[rgdstmap]; -- 2*dstmap.width in 8bpp.
width: NAT ¬ ImagerSample.GetSize[rgdstmap].f;
xMin2: NAT ¬ 2*ImagerSample.GetBox[rgdstmap].min.f;
redscanLine: ImagerSample.SampleBuffer ¬ ImagerSample.ObtainScratchSamples[d.paR.x+d.paR.w];
grnscanLine: ImagerSample.SampleBuffer ¬ ImagerSample.ObtainScratchSamples[d.paR.x+d.paR.w];
bluscanLine: ImagerSample.SampleBuffer ¬ ImagerSample.ObtainScratchSamples[d.paR.x+d.paR.w];
build first set of blocks
IF thisPixel.y >= 0 AND thisPixel.y < redpa.h
THEN {
redpaY ¬ redpa[thisPixel.y];
grnpaY ¬ grnpa[thisPixel.y];
blupaY ¬ blupa[thisPixel.y];
xReps ¬ rUL.x;
FOR x: NAT IN [redpa.x..redpa.x+redpa.w) DO
IF thisPixel.x >= 0 AND thisPixel.x < redpa.w -- check?
THEN {
redscanLine[x]¬ redpaY[thisPixel.x];
grnscanLine[x]¬ grnpaY[thisPixel.x];
bluscanLine[x]¬ blupaY[thisPixel.x];
}
ELSE { redscanLine[x] ¬ 0; grnscanLine[x] ¬ 0; };
xReps ¬ xReps - 1;
IF xReps = 0 THEN {
thisPixel.x ¬ thisPixel.x+1;
xReps ¬ zoom;
};
ENDLOOP;
}
ELSE FOR x: NAT IN [redpa.x..redpa.x+redpa.w) DO
redscanLine[x] ¬ 0;
grnscanLine[x] ¬ 0;
bluscanLine[x] ¬ 0;
ENDLOOP;
yReps ¬ 1+rUL.y;
FOR y: NAT IN [redpa.y..redpa.y+redpa.h) DO
yReps ¬ yReps - 1;
IF yReps = 0 THEN {
leftPixel.y ¬ leftPixel.y+1;
yReps ¬ zoom;
IF leftPixel.y >= 0 AND leftPixel.y < redpa.h
THEN {
redpaY ¬ redpa[leftPixel.y];
grnpaY ¬ grnpa[leftPixel.y];
blupaY ¬ blupa[leftPixel.y];
thisPixel ¬ leftPixel;
xReps ¬ 1+rUL.x;
FOR x: NAT IN [redpa.x..redpa.x+redpa.w) DO
IF thisPixel.x >= 0 AND thisPixel.x < redpa.w
THEN {
redscanLine[x] ¬ redpaY[thisPixel.x];
grnscanLine[x] ¬ grnpaY[thisPixel.x];
bluscanLine[x] ¬ blupaY[thisPixel.x];
}
ELSE {
redscanLine[x] ¬ 0;
grnscanLine[x] ¬ 0;
bluscanLine[x] ¬ 0;
};
xReps ¬ xReps-1;
IF xReps = 0 THEN {
xReps ¬ zoom;
thisPixel.x ¬ thisPixel.x+1;
};
ENDLOOP;
}
ELSE FOR x: NAT IN [redpa.x..redpa.x+redpa.w) DO
redscanLine[x] ¬ 0;
grnscanLine[x] ¬ 0;
bluscanLine[x] ¬ 0;
ENDLOOP;
};
Write the red, starting at 0, with delta.f = 2, thus writing the even bytes:
ImagerSample.PutSamples[rgdstmap2, [y, xMin2], [0, 2], redscanLine, 0, width];
Write the green, starting at 1, with delta.f = 2, thus writing the odd bytes:
ImagerSample.PutSamples[rgdstmap2, [y, 1+xMin2], [0, 2], grnscanLine, 0, width];
Write the blue, which lives in its own channel:
ImagerSample.PutSamples[bdstmap, [y, 0],, bluscanLine, 0, width];
ENDLOOP;
ImagerSample.ReleaseScratchSamples[redscanLine];
ImagerSample.ReleaseScratchSamples[grnscanLine];
ImagerSample.ReleaseScratchSamples[bluscanLine];
};
IF d.maps # NIL THEN SELECT d.maps.bpp FROM
8 => InnerOneMap[d.maps[0].map, d.paR];
24 => {
InnerThreeMaps[d.maps[0].map, d.maps[1].map, d.paR, d.paG, d.paB];
};
ENDCASE;
};
initialize the zooming operation with some preset values
zoom: INT ¬ d.zoomFactor;
center: IntegerPair ¬ d.center;
alpha: INTEGER ¬ (d.zoomFactor-1)/2;
pc: IntegerPair ¬ AddIntegerPairs[center, [-alpha, -alpha]];
beta: IntegerPair¬[Real.Ceiling[pc.x/REAL[zoom]],Real.Ceiling[pc.y/REAL[zoom]]];
rUL: IntegerPair;
d.pUL ¬ AddIntegerPairs[d.poi, [-beta.x, -beta.y]];
d.sUL ¬ AddIntegerPairs[pc, [-beta.x*zoom, -beta.y*zoom]];
rUL ¬ AddIntegerPairs[d.sUL, [zoom, zoom]];
UpdateButtons[d];
[] ← Terminal.ModifyColorFrame[Terminal.Current[], Action];
};
Miscellaneous
Support Procedures
PoiInImage: PROC [d: Tool] RETURNS [BOOLEAN] ~ {
RETURN[d.poi.x>=0 AND d.poi.x<d.paR.x+d.paR.w AND d.poi.y>=0 AND d.poi.y<d.paR.y+d.paR.h];
};
ClipInt: PROC [v, lo, hi: INTEGER] RETURNS [INTEGER] ~ {
RETURN[IF v<lo THEN lo ELSE IF v>hi THEN hi ELSE v];
};
AddIntegerPairs: PROC [pair1, pair2: IntegerPair] RETURNS [sum: IntegerPair] ~ {
sum ¬ [pair1.x+pair2.x, pair1.y+pair2.y];
};
PowerOfTwoRatchet: PROC [val: REAL] RETURNS [new: INT] ~ {
return 2 n such that 2 n <= val <=2 n+1
exp: INT ¬ Real.Round[RealFns.Ln[val]/RealFns.Ln[2.0]];  -- exp ¬ log2 val
RETURN[new ¬ Real.Round[RealFns.Power[2.0, Real.Float[exp]]]];
};
doc: ROPE ¬ FileNames.StripVersionNumber[FS.FileInfo["ColorTrixDoc.tioga"].fullFName];
HelpProc: Buttons.ButtonProc ~ {
v: Viewer ¬ TiogaMenuOps.Open[doc,, left];
TEditSelection.FindRope[v, "Ct Tool"];
};
Debugging Procedures
Debug: PROC [d: Tool] ~ {
rope: ROPE;
rope ¬ IO.PutFR["zoomFactor: %g poi: (%g %g)\n",
IO.int[d.zoomFactor], IO.int[d.poi.x], IO.int[d.poi.y]];
Controls.TypescriptWrite[d.outerData.typescript, rope];
rope ¬ IO.PutFR["sUL: (%g %g) pUL(%g %g)\n",
IO.int[d.sUL.x], IO.int[d.sUL.y], IO.int[d.pUL.y], IO.int[d.pUL.y]];
Controls.TypescriptWrite[d.outerData.typescript, rope];
rope ¬ IO.PutFR["center: (%g %g)\n",
IO.int[d.center.x], IO.int[d.center.y]];
Controls.TypescriptWrite[d.outerData.typescript, rope];
};
Cedar Support Procedures
Destroy: Controls.DestroyProc ~ {
d: Tool ¬ NARROW[clientData];
[] ← Terminal.SetColorCursorPresentation[Terminal.Current[], onesAreBlack];
CtMisc.UnRegisterWatch[[d, ToolMouse, ToolChange]];
};
Start Code
toolUsage: ROPE ~
"Ct Tool
 examine image on the monitor";
icon8bits: Icons.IconFlavor ¬ Icons.NewIconFromFile["ColorTrix.icons", 7];
icon24bits: Icons.IconFlavor ¬ Icons.NewIconFromFile["ColorTrix.icons", 6];
CtDispatch.RegisterCtOp["Image Tools:",  NIL,    NIL];
CtDispatch.RegisterCtOp["Tool",    ToolCmd,   toolUsage];
END.