CtPaintCommandImpl.mesa
Copyright Ó 1990, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, July 3, 1992 3:51 pm PDT
DIRECTORY Buttons, ChoiceButtons, Convert, CtBasic, CtDispatch, CtViewer, ImagerSample, IO, KeyNames, KeyTypes, MessageWindow, Process, Rope, SF, ViewerClasses, ViewerOps, ViewerTools;
CtPaintCommandImpl: CEDAR PROGRAM
IMPORTS Buttons, ChoiceButtons, Convert, CtBasic, CtDispatch, CtViewer, ImagerSample, IO, KeyNames, MessageWindow, Process, SF, ViewerOps, ViewerTools
~ BEGIN
Types and Globals
ButtonProc:  TYPE ~ Buttons.ButtonProc;
IntegerPair:  TYPE ~ CtBasic.IntegerPair;
RGB:    TYPE ~ CtBasic.RGB;
ROPE:    TYPE ~ Rope.ROPE;
Viewer:   TYPE ~ ViewerClasses.Viewer;
control:   KeyTypes.KeySym ¬ KeyNames.KeySymFromName["LeftControl"];
Paint Command
Data:    TYPE ~ REF DataRep;
DataRep:   TYPE ~ RECORD [
cmd:      CtDispatch.CmdHandle ¬ NIL,
pval:      CARDINAL ¬ 100,
rgb:      RGB ¬ [100, 100, 100],
size:      INTEGER ¬ 25,
halfSize:     INTEGER ¬ 12,
paintViewer:    Viewer ¬ NIL,
parent:     Viewer ¬ NIL,
pvalViewer:    Viewer ¬ NIL,
sizeViewer:    Viewer ¬ NIL,
redViewer:    Viewer ¬ NIL,
greenViewer:   Viewer ¬ NIL,
blueViewer:    Viewer ¬ NIL,
functionViewer:   Viewer ¬ NIL,
function:     {paint, blur, incr} ¬ paint
];
ctPaintUsage: ROPE ~ "Ct Paint: interactive painting on a viewer.";
CtPaint: CtDispatch.CtProc ~ {
v: Viewer ¬ ViewerOps.FindViewer["Ct Paint"];
p: Data ¬ IF v = NIL THEN NEW[DataRep] ELSE NARROW[v.data];
p.cmd ¬ cmd;
IF v = NIL THEN TRUSTED {Process.Detach[FORK MakePainter[p]]};
affect ¬ [[0, 0], [0, 0]]; -- caveat painter!
CtViewer.RegisterMouse[p.paintViewer ¬ viewer, MouseProc, p];
};
MakePainter: PROC [p: Data] ~ {
TextButton: PROC [x, y, w: NAT, name, text: ROPE] RETURNS [v: Viewer] ~ {
v ¬ ChoiceButtons.BuildTextPrompt[p.parent, x, y, name, text,, w, p].textViewer;
};
ViewerOps.OpenIcon[p.parent ¬ ViewerOps.CreateViewer[
flavor: $CtPaint,
info: [openHeight: 34, name: "Ct Paint", data: p, column: right, iconic: TRUE]]];
p.sizeViewer ¬ TextButton[0, 3, 40, "size:", "25"];
p.pvalViewer ¬ TextButton[85, 3, 40, "p:", "100"];
p.redViewer ¬ TextButton[150, 3, 40, "r:", "100"];
p.greenViewer ¬ TextButton[215, 3, 40, "g:", "100"];
p.blueViewer ¬ TextButton[280, 3, 40, "b:", "100"];
p.functionViewer ¬ Buttons.Create[
info: [parent: p.parent, name: "paint", wx: 360, wy: 3], proc: Toggle, clientData: p];
};
MouseProc: CtViewer.MouseProc ~ {
p: Data ¬ NARROW[clientData];
IF mouse.state = down AND mouse.button = left
THEN CtViewer.DoWithViewer[p.paintViewer, Paint, p];
};
Paint: CtViewer.ViewerProc ~ {
GetVal: PROC [v: Viewer] RETURNS [i: CARDINAL] ~ {
i ¬ Convert.IntFromRope[ViewerTools.GetContents[v] ! Convert.Error => GOTO Bad];
EXITS Bad=>{MessageWindow.Append["bad value",TRUE];MessageWindow.Blink[]};
};
Poll: CtViewer.PollProc ~ {
IF p.parent.destroyed
THEN RETURN[FALSE]
ELSE {
Blur: PROC ~ {
PixelProc: SAFE PROC [x, y: NAT] ~ {
sum, sumR, sumG, sumB: CARDINAL ¬ 0;
FOR yy: INTEGER IN [y-1..y+1] DO
FOR xx: INTEGER IN [x-1..x+1] DO
IF maps.bpp = 24
THEN {
rgb: RGB ¬ CtBasic.GetRGBPixel[maps, xx, yy];
sumR ¬ sumR+rgb.r; sumG ¬ sumG+rgb.g; sumB ¬ sumB+rgb.b;
}
ELSE sum ¬ sum+CtBasic.GetBWPixel[maps[0].map, xx, yy];
ENDLOOP;
ENDLOOP;
IF maps.bpp = 24
THEN CtBasic.PutRGBPixel[maps, x, y, [sumR/9, sumG/9, sumB/9]]
ELSE CtBasic.PutBWPixel[maps[0].map, x, y, CARDINAL[sum/9]];
};
FOR y: NAT IN [y0..y1] DO
FOR x: NAT IN [x0..x1] DO PixelProc[x, y]; ENDLOOP;
ENDLOOP;
};
Paint: PROC ~ {
IF maps.bpp = 24
THEN CtBasic.PutRGBBox[maps, x0, y0, x1, y1, p.rgb]
ELSE ImagerSample.Fill[maps[0].map, [[y0, x0], [y1, x1]], p.pval];
};
Incr: PROC ~ {
IF maps.bpp = 24
THEN p.rgb ¬ [
BYTE[(NAT[p.rgb.r]+1) MOD 255],
BYTE[(NAT[p.rgb.g]+2) MOD 255],
BYTE[(NAT[p.rgb.b]+3) MOD 255]]
ELSE SELECT dir FROM
positive => IF p.pval = 254 THEN dir ¬ negative ELSE p.pval ¬ p.pval+1;
negative => IF p.pval = 1 THEN dir ¬ positive ELSE p.pval ¬ p.pval-1;
ENDCASE;
Paint[];
};
x0: INTEGER ¬ MAX[maps.x, pos.x-p.halfSize];
y0: INTEGER ¬ MAX[maps.y, pos.y-p.halfSize];
x1: INTEGER ¬ MIN[maps.box.max.f, x0+p.size];
y1: INTEGER ¬ MIN[maps.box.max.s, y0+p.size];
IF x0 # prev.x OR y0 # prev.y THEN {
affect ¬ [SF.Min[affect.min, [y0, x0]], SF.Max[affect.max, [y1, x1]]];
SELECT p.function FROM paint => Paint[]; blur => Blur[]; ENDCASE => Incr[];
prev ¬ [x0, y0];
};
};
};
p: Data ¬ NARROW[clientData];
affect: SF.Box ¬ [[0, 0], [0, 0]];
prev: CtBasic.IntegerPair ¬ [-1, -1];
dir: {positive, negative} ¬ positive;
IF CtViewer.KeyDown[control] THEN { -- pick
pos: IntegerPair ¬ CtViewer.GetMousePos[viewer];
IF maps.bpp = 24
THEN {
rgb: RGB ¬ CtBasic.GetRGBPixel[maps, pos.x, pos.y];
ViewerTools.SetContents[p.redViewer, IO.PutFR1["%g", IO.card[rgb.r]]];
ViewerTools.SetContents[p.greenViewer, IO.PutFR1["%g", IO.card[rgb.g]]];
ViewerTools.SetContents[p.blueViewer, IO.PutFR1["%g", IO.card[rgb.b]]];
}
ELSE {
v: CARDINAL ¬ CtBasic.GetBWPixel[maps[0].map, pos.x, pos.y];
ViewerTools.SetContents[p.pvalViewer, IO.PutFR1["%g", IO.card[v]]];
};
};
p.rgb ¬ [GetVal[p.redViewer], GetVal[p.greenViewer], GetVal[p.blueViewer]];
p.halfSize ¬ (p.size ¬ GetVal[p.sizeViewer])/2;
p.pval ¬ GetVal[p.pvalViewer];
CtViewer.DoWhileMouseDown[viewer, Poll];
CtViewer.PutBuffer[viewer, maps, affect];
};
Destroy: ViewerClasses.DestroyProc ~ {
CtViewer.UnregisterMouse[NARROW[self.data, Data].paintViewer, MouseProc];
};
Toggle: Buttons.ButtonProc ~ {
p: Data ¬ NARROW[clientData];
p.function ¬ SELECT p.function FROM paint => blur, blur => incr, ENDCASE => paint;
Buttons.ReLabel[p.functionViewer,
SELECT p.function FROM paint => "paint", blur => "blur", ENDCASE => "incr"];
};
Start Code
ViewerOps.RegisterViewerClass[$CtPaint, NEW[ViewerClasses.ViewerClassRec¬[destroy:Destroy]]];
CtDispatch.RegisterCtOp["Painting:", NIL, NIL];
CtDispatch.RegisterCtOp["Paint", CtPaint, ctPaintUsage];
END.