PPreViewImpl.mesa
Copyright Ó 1989, 1992 by Xerox Corporation. All rights reserved.
Pier, January 4, 1991 4:28 pm PST
Carl Hauser, August 18, 1989 4:35:28 pm PDT
Michael Plass, March 25, 1992 12:20 pm PST
DIRECTORY
BasicTime, BiScrollers, FunctionCache, FS, Geom2D, Imager, ImagerArtwork, ImagerBackdoor, ImagerColor, ImagerInterpress, ImagerMemory, ImagerPixel, ImagerPixelArray, ImagerTransformation, InputFocus, InterpressInterpreter, IO, MessageWindow, PPreView, PPreViewClient, RasterEncodingStandardIO, Real, Rope, SF, Vector2, ViewerAbort, ViewerClasses, ViewerGroupLocks, ViewerLocks, ViewerPrivate, ViewerTools;
PPreViewImpl:
CEDAR
MONITOR
IMPORTS BiScrollers, FunctionCache, FS, Geom2D, Imager, ImagerArtwork, ImagerBackdoor, ImagerColor, ImagerInterpress, ImagerMemory, ImagerPixel, ImagerPixelArray, ImagerTransformation, InputFocus, InterpressInterpreter, IO, MessageWindow, PPreView, PPreViewClient, Real, Rope, SF, Vector2, ViewerAbort, ViewerGroupLocks, ViewerLocks, ViewerPrivate, ViewerTools
Data: TYPE ~ PPreView.Data;
IPData: TYPE ~ PPreView.IPData;
AISData: TYPE ~ PPreView.AISData;
RESData: TYPE ~ PPreView.RESData;
PaintOp: TYPE ~ PPreView.PaintOp;
Context: TYPE ~ Imager.Context;
Rectangle: TYPE ~ Imager.Rectangle;
Transformation: TYPE ~ ImagerTransformation.Transformation;
Viewer: TYPE ~ ViewerClasses.Viewer;
PProc: TYPE ~ PROC [Context];
CacheKey: TYPE ~ REF CacheKeyRep;
CacheKeyRep:
TYPE ~
RECORD [
fileName: Rope.ROPE,
created: BasicTime.GMT,
pageNumber: INTEGER
];
globalCache: FunctionCache.Cache ¬ FunctionCache.GlobalCache[];
screenResolution: REAL ~ 72.0; -- points per inch
pointsPerInch: REAL ~ 72.0;
oneOverPointsPerInch: REAL ~ 1.0/72.0;
pointsPerMica: REAL ~ 72.0/2540.0;
micasPerPoint: REAL ~ 2540.0/72.0;
pointsPerMeter: REAL ~ 72.0/.0254;
metersPerPoint: REAL ~ .0254/72.0;
grey: CARDINAL ¬ 122645B;
xorStipple: Imager.Color ~ ImagerBackdoor.MakeStipple[stipple: grey, xor: TRUE];
borderWidth: REAL ¬ 2.0;
fudge: REAL ¬ 2.0;
useMessageWindow:
BOOL ¬
FALSE;
Message:
PROC [message: Rope.
ROPE, clearFirst, blink:
BOOL ¬
TRUE] ~ {
MessageWindow.Append[Rope.Concat["PreView: ", message], clearFirst];
IF blink THEN MessageWindow.Blink[];
};
RectangleFromXYs:
PUBLIC PROC [x0, y0, x1, y1:
REAL]
RETURNS [r: Imager.Rectangle] ~ {
IF x0 > x1 THEN {t: REAL ¬ x0; x0 ¬ x1; x1 ¬ t};
IF y0 > y1 THEN {t: REAL ¬ y0; y0 ¬ y1; y1 ¬ t};
r ¬ [x0, y0, x1-x0, y1-y0];
};
PVNotify:
PUBLIC ViewerClasses.NotifyProc ~ {
-- [self: Viewer, input:
LIST OF REF ANY]
ENABLE UNWIND => NULL;
NewMouse:
PROC ~ {
IF InputFocus.GetInputFocus[].owner # self
THEN InputFocus.SetInputFocus[self];
IF b.all
THEN {
dif: Imager.VEC ¬ Vector2.Sub[[mouseX, mouseY], b.origin];
b.p0 ¬ Vector2.Add[b.p0, dif];
b.p1 ¬ Vector2.Add[b.p1, dif];
b.origin ¬ [mouseX, mouseY];
}
ELSE {
IF b.x0 THEN b.p0.x ¬ mouseX ELSE IF b.x1 THEN b.p1.x ¬ mouseX;
IF b.y0 THEN b.p0.y ¬ mouseY ELSE IF b.y1 THEN b.p1.y ¬ mouseY;
};
b.rect ¬ RectangleFromXYs[b.p0.x, b.p0.y, b.p1.x, b.p1.y];
PVFeedback[data: data, v: self, op: change]; --paint grey box
};
mouseX, mouseY: REAL ¬ 0.0;
data: Data ¬ NARROW[BiScrollers.ClientDataOfViewer[self]];
b: PPreView.BBoxState ¬ data.bBox;
IF data.painting THEN RETURN; -- ignore input while painting
FOR list:
LIST
OF
REF
ANY ¬ input, list.rest
UNTIL list =
NIL
DO
WITH list.first
SELECT
FROM
x:
ATOM =>
SELECT x
FROM
$Abort => {
IF b.active THEN PVFeedback[data: data, v: self, op: remove]; -- kill grey bbox
b ¬ []; -- initialization default values cancel current clipping rectangle
};
$Down => {
-- determine user interaction (corner, edge, or center?)
once: BOOL ¬ FALSE;
wOver4, hOver4: REAL;
b.x0 ¬ b.x1 ¬ b.y0 ¬ b.y1 ¬ b.all ¬ FALSE;
IF
NOT b.active
THEN {
b.x1 ¬ b.y1 ¬ TRUE;
b.p0 ¬ b.p1 ¬ [mouseX, mouseY];
b.active ¬ TRUE; -- turn it on and leave it on
RETURN;
};
IF b.p0.x > b.p1.x THEN {t: REAL ¬ b.p0.x; b.p0.x ¬ b.p1.x; b.p1.x ¬ t};
IF b.p0.y > b.p1.y THEN {t: REAL ¬ b.p0.y; b.p0.y ¬ b.p1.y; b.p1.y ¬ t};
wOver4 ¬ (b.p1.x-b.p0.x)/4;
hOver4 ¬ (b.p1.y-b.p0.y)/4;
SELECT mouseX
FROM
< b.p0.x+wOver4 => b.x0 ¬ TRUE;
> b.p1.x-wOver4 => b.x1 ¬ TRUE;
ENDCASE => once ¬ TRUE;
SELECT mouseY
FROM
< b.p0.y+hOver4 => b.y0 ¬ TRUE;
> b.p1.y-hOver4 => b.y1 ¬ TRUE;
ENDCASE =>
IF once
THEN {
b.all ¬ TRUE;
b.origin ¬ [mouseX, mouseY];
};
NewMouse[];
};
$Move => NewMouse[];
$EndMove, $ShowSelection => PPreViewClient.ShowSelection[data, self];
ENDCASE => NULL;
z: BiScrollers.ClientCoords => {
--
TYPE =
REF Vec
mouseX ¬ z.x; -- mouseX in BiScroller coords
mouseY ¬ z.y; -- mouseY in BiScroller coords
IF useMessageWindow
THEN Message[IO.PutFR["%g, %g", IO.real[z.x], IO.real[z.y]], TRUE, FALSE];
};
ENDCASE => Message["unknown input Notify operation"];
ENDLOOP;
};
PVFeedback:
PUBLIC
PROC [data: Data, v: Viewer, op: PPreView.PaintOp ¬ paint] ~ {
ENABLE UNWIND => data.bBox ¬ []; -- kill selection in desperation
Action:
PROC [context: Context] ~ {
-- this context in viewer coords
Show:
PROC [r: Rectangle, updateDimensions:
BOOL ¬
FALSE] ~ {
ctv: Transformation ¬ PPreViewClient.GetTransformation[v];
r ¬ ImagerTransformation.TransformRectangle[m: ctv, r: r];
Imager.MaskRectangle[context, [r.x-5.0, r.y-5.0, 5.0, r.h+10.0]]; -- left side
Imager.MaskRectangle[context, [r.x+r.w, r.y-5.0, 5.0, r.h+10.0]]; -- right side
Imager.MaskRectangle[context, [r.x, r.y-5.0, r.w, 5.0]]; -- top side
Imager.MaskRectangle[context, [r.x, r.y+r.h, r.w, 5.0]]; -- bottom side
IF updateDimensions
THEN {
ViewerTools.SetContents[data.selectionWViewer,
IO.PutFR1["%6.3f",
IO.real[oneOverPointsPerInch*r.w]]];
ViewerTools.SetContents[data.selectionHViewer,
IO.PutFR1["%6.3f",
IO.real[oneOverPointsPerInch*r.h]]];
};
};
IF data.bBox.prev = data.bBox.rect AND op = change THEN RETURN; -- no change
Imager.SetColor[context, xorStipple];
SELECT op
FROM
paint => Show[data.bBox.rect];
remove => {
IF data.abort
THEN data.abort ¬ FALSE
ELSE IF data.bBox.prev # [0., 0., 0., 0.] THEN Show[data.bBox.prev]; -- remove old box
data.bBox.prev ¬ [0.0, 0.0, 0.0, 0.0];
};
change => {
IF data.abort
THEN data.abort ¬ FALSE
ELSE IF data.bBox.prev # [0., 0., 0., 0.] THEN Show[data.bBox.prev]; -- remove old box
Show[data.bBox.rect, TRUE]; -- show new box
};
ENDCASE => Message["unknown feedback operation"];
data.bBox.prev ¬ data.bBox.rect;
};
DirectPaint[viewer: v, action: Action];
};
DoFileOps:
PUBLIC
PROC [
op: PPreView.BBoxOp, viewer: Viewer, data: Data, fileName: Rope.ROPE, clip: BOOL ¬ TRUE]
~ {
ctv: Transformation ¬ PPreViewClient.GetTransformation[viewer];
r: Rectangle ¬ ImagerTransformation.TransformRectangle[m: ctv, r: data.bBox.rect];
clipRect:
REF Rectangle ¬
IF
NOT clip
THEN
NIL
ELSE NEW[Rectangle ¬ ImagerTransformation.InverseTransformRectangle[ctv, r]];
SELECT op
FROM
stuff => {
-- stuff requires clip to be TRUE and bBox valid
DoStuff:
PROC [context: Context] ~ {
DoIt:
PROC ~ {
Imager.ConcatT[context, ctv];
DoPainting[context: context, data: data, viewer: viewer, clipRect: clipRect];
};
Imager.TranslateT[context, [-r.x, -r.y]];
Imager.DoSaveAll[context, DoIt];
IF data.stuffWithBorders
THEN {
Imager.SetStrokeWidth[context, borderWidth];
Imager.SetGray[context, 1];
Imager.MaskVector[context, [r.x, r.y], [r.x, r.y+r.h]]; -- left side
Imager.MaskVector[context, [r.x, r.y], [r.x+r.w, r.y]]; -- bottom side
Imager.MaskVector[context, [r.x+r.w, r.y], [r.x+r.w, r.y+r.h]]; -- right side
Imager.MaskVector[context, [r.x, r.y+r.h], [r.x+r.w, r.y+r.h]]; -- top side
};
};
m: Transformation ¬ ImagerArtwork.Points[];
ImagerArtwork.PasteArtwork[DoStuff, [0, 0, r.w, r.h], m, TRUE, data.stuffWithFit];
};
ipMaster => {
DoIPMaster:
PROC [context: Context] ~ {
Imager.ScaleT[context, metersPerPoint];
IF clip
THEN {
Imager.TranslateT[context, [-r.x, -r.y]];
Imager.ClipRectangle[context, r];
};
Imager.ConcatT[context, ctv];
DoPainting[context: context, data: data, viewer: viewer, clipRect: clipRect];
};
ref: ImagerInterpress.Ref ¬ ImagerInterpress.Create[fileName: fileName !
FS.Error => {
Message[Rope.Concat[error.explanation, " creating IPMaster"]];
GOTO Quit;
}];
ImagerInterpress.DoPage[self: ref, action: DoIPMaster ! Imager.Error => {
Message[Rope.Concat[error.explanation, " creating IPMaster"]];
ImagerInterpress.Close[ref];
GOTO Quit;
}];
ImagerInterpress.Close[ref];
EXITS
Quit => data.abort ¬ TRUE;
};
ENDCASE;
};
DirectPaint:
PROC [viewer: Viewer, action: PProc] ~ {
CallLocked: PROC ~ {ViewerPrivate.PaintClient[viewer, action ! ABORTED => CONTINUE]};
IF viewer = NIL OR viewer.destroyed OR viewer.paintingWedged THEN RETURN;
ViewerGroupLocks.CallRootUnderWriteLock[CallLocked, viewer
! ViewerLocks.Wedged => {viewer.paintingWedged ¬ TRUE; CONTINUE}];
};
DoPainting:
PROC [context: Context, data: Data, viewer: Viewer, clipRect:
REF Rectangle ¬
NIL]
~ {
IF data.clientPaint #
NIL
THEN [] ¬ data.clientPaint[viewer, context, data.clientData, TRUE]
ELSE
WITH data
SELECT
FROM
ipData: IPData => PaintIP[context: context, ipData: ipData]; --kills context variables, but ok
resData: RESData => PaintRES[context: context, resData: resData, clipRect: clipRect];
aisData: AISData => PaintAIS[context: context, aisData: aisData, clipRect: clipRect];
pressData: PressData => PaintPress[context: context, pressData: pressData];
pdData: PDData => PaintPD[context: context, pdData: pdData, viewer: viewer];
gData: GData => PaintGriffin[context: context, gData: gData];
pvData: PVData => PaintGG[context: context, pvData: pvData];
ENDCASE => Message["unknown paint operation"];
};
PaintIP:
PROC [context: Context, ipData: IPData] ~ {
ENABLE {
Imager.Error => {
Message[Rope.Concat[error.explanation, ". Use -M switch to preview this file."]];
GOTO Null; -- return cleanly from painting
};
Imager.Warning => RESUME;
};
IF ipData.ipMaster #
NIL
THEN
SELECT
TRUE
FROM
ipData.switches['M] => {
-- M switch means use no ImagerMemory
selected: BOOL ¬ FALSE;
Imager.SetGray[context, 1];
Imager.ScaleT[context, pointsPerMeter]; -- establish IP coord system
InterpressInterpreter.DoPage[ipData.ipMaster, ipData.pageNumber, context, PPreView.IPLogError];
};
ipData.pageInMem=ipData.pageNumber => {
-- iMemContext is current
ImagerMemory.Replay[c: ipData.iMemContext, into: context];
};
ipData.pageInMem#ipData.pageNumber => {
-- memory context may be cached
PageCompareProc: FunctionCache.CompareProc ~ {
PROC [argument: Domain] RETURNS [good: BOOL];
RETURN[NARROW[argument, CacheKey] = cacheKey];
};
cacheKey: CacheKey ¬
NEW[CacheKeyRep ¬
[ipData.fileInfo.fullFName, ipData.fileInfo.created, ipData.pageNumber]];
IF (ipData.iMemContext ¬
NARROW[FunctionCache.Lookup[x: globalCache, compare: PageCompareProc, clientID: $PVPage].value, Imager.Context])#
NIL
THEN {
-- hit
ImagerMemory.Replay[c: ipData.iMemContext, into: context];
ipData.pageInMem ¬ ipData.pageNumber;
}
ELSE {
-- miss
ipData.iMemContext ¬ ImagerMemory.NewMemoryContext[];
Imager.SetGray[ipData.iMemContext, 1];
Imager.ScaleT[ipData.iMemContext, pointsPerMeter]; -- establish IP coord system
InterpressInterpreter.DoPage[
ipData.ipMaster, ipData.pageNumber, ipData.iMemContext, PPreView.IPLogError];
FunctionCache.Insert[x: globalCache, argument: cacheKey, value: ipData.iMemContext,
size: ImagerMemory.GetContextSize[ipData.iMemContext], clientID: $PVPage];
ipData.pageInMem ¬ ipData.pageNumber;
ImagerMemory.Replay[c: ipData.iMemContext, into: context];
};
};
ENDCASE => NULL;
};
<<PaintPress:
PROC [context: Context, pressData: PressData] ~ {
Imager.SetGray[context, 1];
Imager.ScaleT[context, pointsPerMica]; -- establish Press coord system
ShowPress.DrawPressPage[context, pressData.presshandle, pressData.pageNumber
! ShowPress.ShowPressError => {
Message[Atom.GetPName[code]];
pressData.abort ¬ TRUE;
CONTINUE;
}];
};
>>
<<PaintPD:
PROC [context: Context, pdData: PDData, viewer: Viewer] ~ {
PaintIt:
PROC [self: Viewer, whatChanged:
REF
ANY] ~ {
This routine may be called many times; it shouldn't do destructive operations on context state
pdData: PDData ¬ NARROW[BiScrollers.ClientDataOfViewer[self]];
WITH whatChanged
SELECT
FROM
handle: PDImageReader.Handle => Imager.DrawBitmap[
context: context, bitmap: handle.bitmap, position: [0,pdData.pdhandle.herald.imageSSize]];
ENDCASE => ERROR;
};
IF pdData.scalePD
THEN Imager.Scale2T[context, pdData.scaleFactors];-- do only once (outside of paintAction)
Reset the handle in pdData to the image in pdData.pageNumber, then interpret the image
IF PDImageReader.ResetToImage[pdData: pdData]#NIL THEN [] ¬ PDImageReader.InterpretImage[handle: pdData.pdhandle, viewer: viewer, paintAction: PaintIt]; --this guy eventually calls PaintIt.
IF PDImageReader.ResetToImage[pdData: pdData]#NIL THEN IF NOT pdData.abort THEN [] ← PDImageReader.InterpretImage[handle: pdData.pdhandle, viewer: viewer, paintAction: PaintIt]; --this guy eventually calls PaintIt.
};
>>
ClipPixelArray:
PROC [pa: ImagerPixelArray.PixelArray, clipRectangle: Rectangle]
RETURNS [new: ImagerPixelArray.PixelArray]
~ {
MaxSample:
PROC [i:
NAT]
RETURNS [ImagerPixel.Sample] ~ {
RETURN [ImagerPixelArray.MaxSampleValue[pa, i]]
};
paRect: Rectangle ¬ ImagerTransformation.InverseTransformRectangle[m: pa.m, r: clipRectangle];
paBox: SF.Box = SF.Intersect[[max: [pa.sSize, pa.fSize]], [min: [s: Real.Floor[paRect.x], f: Real.Floor[paRect.y]], max: [s: Real.Ceiling[paRect.x+paRect.w], f: Real.Ceiling[paRect.y+paRect.h]]]];
pixelMap: ImagerPixel.PixelMap = ImagerPixel.NewPixelMap[samplesPerPixel: pa.samplesPerPixel, box: paBox, maxSample: MaxSample];
FOR i:
NAT
IN [0..pixelMap.samplesPerPixel)
DO
ImagerPixelArray.Transfer[pa: pa, i: i, s: paBox.min.s, f: paBox.min.f, dst: pixelMap[i], dstMin: paBox.min, size: SF.Size[paBox]];
ENDLOOP;
new ¬ ImagerPixelArray.FromPixelMap[pixelMap: pixelMap, box: paBox, scanMode: [slow: right, fast: up], immutable: TRUE];
new.m ¬ ImagerTransformation.PreTranslate[pa.m, [paBox.min.s, paBox.min.f]];
};
PaintAIS:
PROC [context: Context, aisData: AISData, clipRect:
REF Rectangle] ~ {
state: PPreView.AISState ¬ aisData.state;
pa: ImagerPixelArray.PixelArray ¬ state.pa;
IF state.active
THEN {
IF clipRect#NIL THEN { pa ¬ ClipPixelArray[pa, clipRect] };
IF state.op =
NIL
THEN {
Imager.SetGray[context, 1];
Imager.MaskPixel[context: context, pa: pa]
}
ELSE Imager.DrawSampledColor[context: context, pa: pa, colorOperator: state.op];
};
};
PaintRES:
PROC [context: Context, resData: RESData, clipRect:
REF Rectangle] ~ {
res: RasterEncodingStandardIO.RES = resData.image;
maskImage: ImagerPixelArray.PixelArray ¬ res.maskImage;
colorImage: ImagerPixelArray.PixelArray ¬ res.colorImage;
MaskPABounds:
PROC [pa: ImagerPixelArray.PixelArray] ~ {
Inner:
PROC ~ {
Imager.ConcatT[context, pa.m];
Imager.MaskRectangle[context, [0, 0, pa.sSize, pa.fSize]];
};
Imager.DoSave[context, Inner];
};
IF clipRect#
NIL
THEN {
IF maskImage # NIL THEN maskImage ¬ ClipPixelArray[maskImage, clipRect];
IF colorImage # NIL THEN colorImage ¬ ClipPixelArray[colorImage, clipRect];
};
SELECT
TRUE
FROM
colorImage #
NIL
AND maskImage=
NIL
AND res.colorOperator #
NIL
AND res.colorOperator.samplesPerPixelIn = 1
AND ImagerPixelArray.MaxSampleValue[colorImage, 0] = 1 => {
sample: CARDINAL ¬ 0;
Pixel: PROC [NAT] RETURNS [REAL] ~ { RETURN [sample] };
maskImage ¬ colorImage;
colorImage ¬ NIL;
sample ¬ 0;
Imager.SetColor[context, ImagerColor.ColorFromPixel[res.colorOperator, Pixel]];
MaskPABounds[maskImage];
sample ¬ 1;
Imager.SetColor[context, ImagerColor.ColorFromPixel[res.colorOperator, Pixel]];
};
colorImage =
NIL
OR res.colorOperator =
NIL => {
Imager.SetGray[context, 1];
};
ENDCASE => { Imager.SetSampledColor[context, colorImage, NIL, res.colorOperator] };
IF maskImage=
NIL
THEN Imager.MaskRectangle[context, ImagerTransformation.TransformRectangle[m: colorImage.m, r: [0, 0, colorImage.sSize, colorImage.fSize]]]
ELSE Imager.MaskPixel[context, maskImage];
};
<<PaintGriffin:
PROC [context: Context, gData: GData] ~ {
SELECT
TRUE
FROM
gData.switches['M] => {
-- M switch means use no ImagerMemory
Imager.ScaleT[context, pointsPerMica]; -- establish Griffin coord. system
Imager.SetStrokeJoint[context, round]; -- avoid miter problems
GriffinImageUtils.GriffinToImagerCalls[context, gData.image];
};
gData.pageInMem=gData.pageNumber => {
-- iMemContext is current
ImagerMemory.Replay[c: gData.iMemContext, into: context];
};
gData.pageInMem#gData.pageNumber => {
-- memory context may be cached
PageCompareProc: FunctionCache.CompareProc ~ {
PROC [argument: Domain] RETURNS [good: BOOL];
RETURN[NARROW[argument, CacheKey] = cacheKey];
};
cacheKey: CacheKey ¬ NEW[CacheKeyRep ¬ [gData.fileInfo.fullFName, gData.fileInfo.created, gData.pageNumber]];
IF (gData.iMemContext ¬
NARROW[FunctionCache.Lookup[x: globalCache, compare: PageCompareProc, clientID: $PVPage].value, Context])#
NIL
THEN {
--hit
ImagerMemory.Replay[c: gData.iMemContext, into: context];
gData.pageInMem ¬ gData.pageNumber;
}
ELSE {
-- miss
gData.iMemContext ¬ ImagerMemory.NewMemoryContext[];
Imager.ScaleT[gData.iMemContext, pointsPerMica]; -- establish Griffin coord. system
Imager.SetStrokeJoint[gData.iMemContext, round]; -- avoid miter problems
GriffinImageUtils.GriffinToImagerCalls[gData.iMemContext, gData.image];
FunctionCache.Insert[x: globalCache, argument: cacheKey, value: gData.iMemContext, size: ImagerMemory.GetContextSize[gData.iMemContext], clientID: $PVPage];
gData.pageInMem ¬ gData.pageNumber;
ImagerMemory.Replay[c: gData.iMemContext, into: context];
};
};
ENDCASE => NULL;
};
>>
<<PaintGG:
PROC [context: Context, pvData: PVData] ~ {
SELECT
TRUE
FROM
pvData.switches['M] => {
-- M switch means use no ImagerMemory
Imager.ScaleT[context, pointsPerInch]; -- establish GG coord. system
GGForPV.DrawData[context, pvData.data];
};
pvData.pageInMem=pvData.pageNumber => {
-- iMemContext is current
ImagerMemory.Replay[c: pvData.iMemContext, into: context];
};
pvData.pageInMem#pvData.pageNumber => {
-- memory context may be cached
PageCompareProc: FunctionCache.CompareProc ~ {
PROC [argument: Domain] RETURNS [good: BOOL];
RETURN[NARROW[argument, CacheKey] = cacheKey];
};
cacheKey: CacheKey ¬
NEW[CacheKeyRep ¬
[pvData.fileInfo.fullFName, pvData.fileInfo.created, pvData.pageNumber]];
IF (pvData.iMemContext ¬
NARROW[FunctionCache.Lookup[x: globalCache, compare: PageCompareProc, clientID: $PVPage].value, Context])#
NIL
THEN {
--hit
ImagerMemory.Replay[c: pvData.iMemContext, into: context];
pvData.pageInMem ¬ pvData.pageNumber;
}
ELSE {
-- miss
pvData.iMemContext ¬ ImagerMemory.NewMemoryContext[];
Imager.ScaleT[pvData.iMemContext, pointsPerInch]; -- establish GG coord. system
GGForPV.DrawData[pvData.iMemContext, pvData.data];
FunctionCache.Insert[x: globalCache, argument: cacheKey, clientID: $PVPage, size: ImagerMemory.GetContextSize[pvData.iMemContext], value: pvData.iMemContext];
pvData.pageInMem ¬ pvData.pageNumber;
ImagerMemory.Replay[c: pvData.iMemContext, into: context];
};
};
ENDCASE => NULL;
};
>>
PVPaint:
PUBLIC
ENTRY ViewerClasses.PaintProc ~
TRUSTED {
[self: Viewer, context: Context, whatChanged: REF ANY, clear: BOOL];
ENABLE ABORTED => GOTO Finished; -- return and unlock viewers
data: Data ¬ NARROW[BiScrollers.ClientDataOfViewer[self]];
BEGIN
ENABLE UNWIND => data.painting ¬ FALSE; -- abort is set, painting gets cleared
PVPaintWithAbort:
PROC ~
TRUSTED {
data.abort ¬ data.painting ¬ TRUE;
DoPainting[context: context, data: data, viewer: self];
data.abort ¬ data.painting ¬ FALSE;
IF data.bBox.active THEN PVFeedback[data: data, v: self, op: paint];
};
ViewerAbort.CallWithAbortEnabled[self, PVPaintWithAbort];
END;
};
PVDestroy:
PUBLIC
ENTRY ViewerClasses.DestroyProc ~ {
-- [self: Viewer]
ENABLE UNWIND => NULL;
data: Data ¬ NARROW[BiScrollers.ClientDataOfViewer[self]];
WITH data
SELECT
FROM
ipData: IPData => {
IF ipData.ipMaster # NIL THEN InterpressInterpreter.Close[master: ipData.ipMaster];
ipData.ipMaster ¬ NIL;
};
resData: RESData => {
resData.image ¬ NIL;
};
aisData: AISData => {
AIS.CloseFile[aisData.state.openFile];
aisData.state.openFile ← NIL;
aisData.state.pa ¬ NIL;
aisData.state.op ¬ NIL;
};
pressData: PressData => {
ShowPress.Close[pressData.presshandle];
pressData.presshandle ← NIL;
};
pdData: PDData => {
PDFileReader.Close[pdData.pdhandle];
pdData.pdhandle ← NIL;
pdData.image ← NIL;
};
gData: GData => {
gData.image ← NIL;
};
pvData: PVData => {
pvData.data ← NIL;
};
ENDCASE => Message["unknown destroy operation"];
SafeStorage.ReclaimCollectibleObjects[suspendMe: FALSE]; -- good citizenship
};
PVGetName:
PUBLIC ViewerClasses.GetProc ~ {
[self: Viewer, op: ATOM] RETURNS [data: REF ANY]
This PROC for the benefit of XTSetter, which calls this when the InputFocus is in the previewer and the XTSetter GET button is clicked
RETURN[NARROW[BiScrollers.ClientDataOfViewer[self], Data].container.file];
};
PVBasicTransformProc:
PUBLIC
PROC [bs: BiScrollers.BiScroller]
RETURNS [Transformation] ~ {
BiScrollers.TransformGenerator
actionArea: Viewer ¬ bs.style.QuaViewer[bs: bs, inner: TRUE];
data: Data ¬ NARROW[BiScrollers.ClientDataOfViewer[actionArea]];
Put the center of the client specified size in the middle of the window.
height: REAL ¬ data.pageHeight;
width: REAL ¬ data.pageWidth;
ww: REAL ¬ actionArea.ww;
wh: REAL ¬ actionArea.wh;
RETURN[ImagerTransformation.Translate[[(ww-width)/2.0, (wh-height)/2.0]]];
};
PVExtremaProc:
PUBLIC
PROC [clientData:
REF
ANY, direction: Vec]
RETURNS [min, max: Vec]
~ { --BiScrollers.ExtremaProc
This proc is required by BiScrollers to return the extremes of the displayed data
data: Data ¬ NARROW[clientData];
area: Geom2D.Rect ¬ [x: 0.0, y: 0.0, w: data.pageWidth, h: data.pageHeight];
[min, max] ¬ Geom2D.ExtremaOfRect[r: area, n: direction];
};
END.
..
Old Preview.tip
SELECT TRIGGER FROM
Mouse
WHILE Red Down => Coords, Move;
Red Down =>
SELECT
ENABLE
FROM
Yellow Down => Abort;
ENDCASE => Coords, Move;
Yellow Down => Abort;
Red Up => EndMove;
Blue Up => ShowSelection;
ENDCASE.