ViewerContextsImpl.Mesa
Copyright Ó 1990, 1992 by Xerox Corporation. All rights reserved.
Last tweaked by Mike Spreitzer on February 20, 1992 11:34 am PST
Willie-s, April 21, 1992 5:24 pm PDT
DIRECTORY Atom, BasicTime, Icons, Imager, ImagerBackdoor, ImagerColor, ImagerPath, ImagerPrivate, ImagerTransformation, InputFocus, IO, MessageWindow, MJSContainers, PopUpButtons, Process, Real, Rope, Rules, SF, TIPUser, ViewerClasses, ViewerContexts, ViewerLocks, ViewerOps, ViewerPrivate, ViewerTools;
ViewerContextsImpl:
CEDAR
MONITOR
IMPORTS Atom, Icons, Imager, ImagerBackdoor, ImagerColor, ImagerPath, ImagerPrivate, ImagerTransformation, InputFocus, IO, MessageWindow, MJSContainers, PopUpButtons, Process, Real, Rules, TIPUser, ViewerLocks, ViewerOps, ViewerPrivate, ViewerTools
EXPORTS Imager, ViewerContexts
=
BEGIN OPEN Ctrs:MJSContainers, IT:ImagerTransformation, PUB:PopUpButtons, ViewerContexts;
LORA: TYPE ~ LIST OF REF ANY;
ROPE: TYPE ~ Rope.ROPE;
VEC: TYPE ~ Imager.VEC;
Rectangle: TYPE ~ Imager.Rectangle;
Xfm: TYPE ~ IT.Transformation;
PixelArray: TYPE ~ Imager.PixelArray;
SampleMap: TYPE ~ Imager.SampleMap;
PixelMap: TYPE ~ Imager.PixelMap;
ScanMode: TYPE ~ Imager.ScanMode;
Color: TYPE ~ Imager.Color;
Font: TYPE ~ Imager.Font;
ColorOperator: TYPE ~ Imager.ColorOperator;
XStringProc: TYPE ~ Imager.XStringProc;
Clipper: TYPE ~ ImagerBackdoor.Clipper;
Outline: TYPE ~ ImagerPath.Outline;
PathProc: TYPE ~ ImagerPath.PathProc;
ViewerList: TYPE ~ LIST OF Viewer;
ContextList: TYPE ~ LIST OF Context;
Class: TYPE ~ REF ClassRep;
ClassRep: PUBLIC TYPE ~ ImagerPrivate.ClassRep;
ContextViewer: TYPE ~ REF ContextViewerPrivate;
ContextViewerPrivate:
PUBLIC
TYPE ~
RECORD [
size: VECI,
NoteClear: PROC [clientData: REF ANY],
NoteChange: PROC [clientData: REF ANY, idealToViewer, viewerToScreen, viewerSize, idealSize: VECI],
NoteDestruction: PROC [clientData: REF ANY],
clientData: REF ANY,
scrollable: BOOL,
ctr, inner, rule, menuPane: Viewer ¬ NIL,
sizeButton, scrollCtl: Viewer ¬ NIL,
panes: ViewerList ¬ NIL, --includes menu pane
menuWidth: INTEGER ¬ 0,
ctxs: ContextList ¬ NIL,
i2w, w2s, i2s: VECI ¬ [0, 0], --ideal to viewer, viewer to screen, ideal to screen
vcs: VECI ¬ [0, 0], --viewer clip size
scbKnown: BOOL ¬ FALSE,
scb: BoxI ¬ [0, 0, 0, 0], --screen clip box
focused: BOOL ¬ FALSE, --have input focus
needClear: BOOL ¬ FALSE, --need to clear before painting
wantOut: BOOL ¬ FALSE, --paint would like to exit
in: BOOL ¬ FALSE, --the viewer lock is held
cIn: ViewerContext ¬ NIL, --the context, if any, accessing viewer data
wantIn: INTEGER ¬ 0, --how many contexts want the viewer lock to be held
stayIn: StayList ¬ NIL, --other reasons to hold the viewer lock
destroyed: BOOL ¬ FALSE,
change: CONDITION];
ViewerContext: TYPE ~ REF ViewerContextPrivate;
ViewerContextPrivate:
TYPE ~
RECORD [
cv: ContextViewer,
base: Context,
baseClass: Class,
viewToIdeal: VECI ¬ [0, 0],
clipList: ClipList ¬ NIL,
valid: BOOL ¬ TRUE,
destroyed: BOOL ¬ FALSE];
StayList: TYPE ~ LIST OF Stay;
Stay: TYPE ~ RECORD [def: StayDef, name: ROPE ¬ NIL];
StayDef: TYPE ~ RECORD [vc: ViewerContext, reason: StayReason, name: ATOM ¬ NIL, where: RectI ¬ [0, 0, 0, 0]];
StayReason: TYPE ~ {savedBuffer, doWithBuffer};
ClipList: TYPE ~ LIST OF ClipItem;
ClipItem:
TYPE ~
RECORD [
exclude: BOOL,
shape:
SELECT kind: *
FROM
rect => [ri: RectI],
outline => [o: Outline, oddWrap: BOOL],
ENDCASE];
RectI: TYPE ~ RECORD [x, y, w, h: INTEGER];
BoxI: TYPE ~ RECORD [xmin, ymin, xmax, ymax: INTEGER];
idXfm: Xfm ~ IT.Translate[[0, 0]];
msHold: INTEGER ¬ 1000;
ruleHeight: INTEGER ¬ 3;
tip: TIPUser.TIPTable ~ TIPUser.InstantiateNewTIPTable["ContextViewer.tip"];
icon: Icons.IconFlavor ¬ Icons.NewIconFromFile["ContextViewer.icons", 0];
ctrFlavor: ATOM ~ $ContextViewerContainer;
ctrClass: Ctrs.MJSContainerClass ~
NEW [Ctrs.MJSContainerClassRep ¬ [
icon: icon]];
alignerName: PUB.Image ~ PUB.ImageForRope["Align"];
alignerClass:
PUB.Class ~
PUB.MakeClass[[
proc: CVPop,
choices:
LIST[
[LIST[$Left, $Top]],
[LIST[$Top]],
[LIST[$Right, $Top]],
[LIST[$Left]],
[LIST[$HCenter, $VCenter]],
[LIST[$Right]],
[LIST[$Left, $Bottom]],
[LIST[$Bottom]],
[LIST[$Right, $Bottom]]
],
doc: "various alignment ops"]];
menuHeight: INTEGER ¬ Real.Ceiling[alignerName.size.y];
menuSep: INTEGER ¬ menuHeight;
destroyerClass:
PUB.Class ~
PUB.MakeClass[[
proc: CVPop,
choices: LIST[ [$Destroy] ],
doc: "destroy this viewer"]];
sizeClass:
PUB.Class ~
PUB.MakeClass[[
proc: CVPop,
choices: LIST[[$SetSize, "Set size"], [$FitSize, "Set ideal size to current visible size"]]
]];
toScrollableClass:
PUB.Class ~
PUB.MakeClass[[
proc: CVPop,
choices: LIST[[$ToScrollable, "-> Scrollable"]],
image: PUB.ImageForRope["-> Scrollable"]
]];
toUnscrollableClass:
PUB.Class ~
PUB.MakeClass[[
proc: CVPop,
choices: LIST[[$ToUnscrollable, "-> Unscrollable"]],
image: PUB.ImageForRope["-> Unscrollable"]
]];
vcClass: Class ~
NEW [ClassRep ¬ [
type: $ViewerContext,
Save: VCSave,
Restore: VCRestore,
SetInt: VCSetInt,
SetReal: VCSetReal,
SetT: VCSetT,
SetFont: VCSetFont,
SetColor: VCSetColor,
SetClipper: VCSetClipper,
GetInt: VCGetInt,
GetReal: VCGetReal,
GetT: VCGetT,
GetFont: VCGetFont,
GetColor: VCGetColor,
GetClipper: VCGetClipper,
ConcatT: VCConcatT,
Scale2T: VCScale2T,
RotateT: VCRotateT,
TranslateT: VCTranslateT,
Move: VCMove,
SetXY: VCSetXY,
SetXYRel: VCSetXYRel,
GetCP: VCGetCP,
StartUnderline: VCStartUnderline,
MaskUnderline: VCMaskUnderline,
CorrectMask: VCCorrectMask,
CorrectSpace: VCCorrectSpace,
Space: VCSpace,
SetCorrectMeasure: VCSetCorrectMeasure,
SetCorrectTolerance: VCSetCorrectTolerance,
Correct: VCCorrect,
DontCorrect: VCDontCorrect,
SetGray: VCSetGray,
SetSampledColor: VCSetSampledColor,
SetSampledBlack: VCSetSampledBlack,
Clip: VCClip,
ClipRectangle: VCClipRectangle,
ClipRectangleI: VCClipRectangleI,
Show: VCShow,
ShowBackward: VCShowBackward,
MaskFill: VCMaskFill,
MaskRectangle: VCMaskRectangle,
MaskStroke: VCMaskStroke,
MaskPixel: VCMaskPixel,
ShowAndFixedXRel: VCShowAndFixedXRel,
ShowText: VCShowText,
MaskRectangleI: VCMaskRectangleI,
MaskVector: VCMaskVector,
MaskDashedStroke: VCMaskDashedStroke,
MaskBitmap: VCMaskBitmap,
DrawBitmap: VCDrawBitmap,
DrawPixels: VCDrawPixels,
DoIfVisible: VCDoIfVisible,
DoWithBuffer: VCDoWithBuffer,
DrawObject: VCDrawObject,
GetBounds: VCGetBounds,
ViewReset: VCViewReset,
ViewTranslateI: VCViewTranslateI,
ViewClip: VCViewClip,
ViewClipRectangleI: VCViewClipRectangleI,
GetTransformation: VCGetTransformation,
Transform: ImagerPrivate.DefaultTransform,
MoveViewRectangle: VCMoveViewRectangle,
TestViewRectangle: VCTestViewRectangle,
GetBufferColorOperator: VCGetBufferColorOperator,
AccessBuffer: ImagerPrivate.DefaultAccessBuffer,
SaveBuffer: VCSaveBuffer,
RestoreBuffer: VCRestoreBuffer,
DiscardBuffer: VCDiscardBuffer,
propList: NIL]];
Create:
PUBLIC
PROC
[viewerInit: ViewerClasses.ViewerRec,
size: VECI,
NoteClear: PROC [clientData: REF ANY] ¬ NIL,
NoteChange: PROC [clientData: REF ANY, idealToViewer, viewerToScreen, viewerSize, idealSize: VECI] ¬ NIL,
NoteDestruction: PROC [clientData: REF ANY] ¬ NIL,
clientData: REF ANY ¬ NIL]
RETURNS [cv: ContextViewer] ~ {
unique: REF ROPE ~ NEW [ROPE ¬ "Another Context Viewer Class"];
ua: CARD ~ LOOPHOLE[unique];
cvClass: ViewerClasses.ViewerClass ~
NEW [ViewerClasses.ViewerClassRec ¬ [
flavor: Atom.MakeAtom[IO.PutFR1["ContextViewer[%g]", [cardinal[ua]] ]],
notify: Notify,
paint: Paint,
modify: CVModify,
destroy: CVDestroy,
scroll: Scroll,
hscroll: HScroll,
tipTable: tip,
icon: icon,
props: NIL]];
innerScroll: RECORD [x, y: BOOL] ~ [viewerInit.hscrollable, viewerInit.scrollable];
ViewerOps.RegisterViewerClass[cvClass.flavor, cvClass];
cv ¬ NEW [ContextViewerPrivate ¬ [size, NoteClear, NoteChange, NoteDestruction, clientData, viewerInit.scrollable]];
TRUSTED {Process.InitializeCondition[@cv.change, Process.MsecToTicks[5000]];
Process.EnableAborts[@cv.change]};
viewerInit.hscrollable ¬ viewerInit.scrollable ¬ FALSE;
viewerInit.data ¬ cv;
cv.ctr ¬ Ctrs.Create[ctrFlavor, viewerInit];
cv.menuPane ¬ CreateMenuPane[cv];
Ctrs.ChildXBound[cv.ctr, cv.menuPane];
cv.panes ¬ LIST[cv.menuPane];
cv.rule ¬ Rules.Create[[name: "the rule", parent: cv.ctr, wy: cv.menuPane.wh, ww: cv.ctr.cw, wh: ruleHeight]];
Ctrs.ChildXBound[cv.ctr, cv.rule];
cv.inner ¬ ViewerOps.CreateViewer[cvClass.flavor, [wy: cv.menuPane.wh+1, ww: cv.ctr.cw, wh: cv.ctr.ch-cv.menuPane.wh-1, name: "inner", scrollable: TRUE, hscrollable: TRUE, border: FALSE, parent: cv.ctr, data: cv]];
Ctrs.ChildXBound[cv.ctr, cv.inner];
Ctrs.ChildYBound[cv.ctr, cv.inner];
TRUSTED {Process.Detach[FORK PaintDriver[cv]]};
RETURN};
QuaViewer:
PUBLIC
PROC [cv: ContextViewer, which: WhichViewer]
RETURNS [Viewer] ~ {
SELECT which
FROM
inner => RETURN [cv.inner];
outer => RETURN [cv.ctr];
ENDCASE => ERROR};
QuaContextViewer:
PUBLIC
PROC [v: Viewer]
RETURNS [MaybeContextViewer] ~ {
IF v.class.flavor = ctrFlavor THEN RETURN [[TRUE, NARROW[Ctrs.GetClientData[v], ContextViewer]]];
WITH v.data
SELECT
FROM
x: ContextViewer => RETURN [[TRUE, x]];
ENDCASE => NULL;
RETURN [[FALSE, NIL]]};
DoWithInfo:
PUBLIC
PROC [cv: ContextViewer,
With:
PROC [idealToViewer, viewerToScreen, viewerSize, idealSize:
VECI, destroyed:
BOOL]] ~ {
XfmsWithLock:
PROC ~ {
With[cv.i2w, cv.w2s, [cv.inner.cw, cv.inner.ch], cv.size, cv.destroyed OR cv.ctr.destroyed];
RETURN};
ViewerLocks.CallUnderWriteLock[XfmsWithLock, cv.inner];
RETURN};
SetIdealSize:
PUBLIC
PROC [cv: ContextViewer, size:
VECI] ~ {
SetIdealSizeWithLock:
ENTRY
PROC ~ {
ENABLE UNWIND => NULL;
cv.size ¬ size;
PUB.AmbushInstance[button: cv.sizeButton, image: ImageForSize[cv.size], specImage: TRUE];
IF cv.NoteChange#NIL THEN cv.NoteChange[cv.clientData, cv.i2w, cv.w2s, cv.vcs, cv.size];
RETURN};
ViewerLocks.CallUnderWriteLock[SetIdealSizeWithLock, cv.sizeButton];
RETURN};
GetMenuPane:
PUBLIC
PROC [cv: ContextViewer]
RETURNS [Viewer]
~ {RETURN [cv.menuPane]};
AddMenuElt:
PUBLIC
PROC [cv: ContextViewer, elt: Viewer, paint:
BOOL] ~ {
AddEltWithLock:
PROC ~ {
ViewerOps.EstablishViewerPosition[elt, cv.menuWidth+menuSep, 0, elt.ww, elt.wh];
cv.menuWidth ¬ cv.menuWidth + menuSep + elt.ww;
IF elt.wh > cv.menuPane.ch
THEN {
ViewerOps.EstablishViewerPosition[cv.menuPane, 0, cv.menuPane.wy, cv.menuPane.ww, elt.wh];
Reposition[cv, paint]}
ELSE IF paint THEN ViewerOps.PaintViewer[elt, all, TRUE];
RETURN};
ViewerLocks.CallUnderWriteLock[AddEltWithLock, cv.ctr];
RETURN};
AddPane:
PUBLIC
PROC [cv: ContextViewer, pane: Viewer, above, paint:
BOOL] ~ {
AddWithLock:
PROC ~ {
IF above THEN cv.panes ¬ CONS[pane, cv.panes]
ELSE {last: ViewerList ¬ cv.panes;
WHILE last.rest#NIL DO last ¬ last.rest ENDLOOP;
last.rest ¬ LIST[pane]};
Ctrs.ChildXBound[cv.ctr, pane];
Reposition[cv, paint];
RETURN};
ViewerLocks.CallUnderWriteLock[AddWithLock, cv.ctr];
RETURN};
DeletePane:
PUBLIC
PROC [cv: ContextViewer, pane: Viewer, paint:
BOOL] ~ {
err: BOOL ¬ FALSE;
DeleteWithLock:
PROC ~ {
last: ViewerList ¬ NIL;
FOR pl: ViewerList ¬ cv.panes, pl.rest
WHILE pl#
NIL
DO
IF pl.first=pane
THEN {
IF last=NIL THEN cv.panes ¬ pl.rest ELSE last.rest ¬ pl.rest;
ViewerOps.DestroyViewer[pane, FALSE];
Reposition[cv, paint];
RETURN};
ENDLOOP;
err ¬ TRUE};
IF pane = cv.menuPane THEN ERROR;
ViewerLocks.CallUnderWriteLock[DeleteWithLock, cv.ctr];
IF err THEN ERROR;
RETURN};
Reposition:
PROC [cv: ContextViewer, paint:
BOOL] ~ {
y: INTEGER ¬ 0;
FOR pl: ViewerList ¬ cv.panes, pl.rest
WHILE pl#
NIL
DO
ViewerOps.EstablishViewerPosition[pl.first, 0, y, cv.ctr.cw, pl.first.wh];
y ¬ y + pl.first.wh;
ENDLOOP;
ViewerOps.EstablishViewerPosition[cv.rule, 0, y, cv.ctr.cw, ruleHeight];
ViewerOps.EstablishViewerPosition[cv.inner, 0, y+ruleHeight, cv.ctr.cw, cv.ctr.ch-y-ruleHeight];
IF paint THEN ViewerOps.PaintViewer[cv.ctr, client, TRUE];
RETURN};
CreateContext:
PUBLIC
PROC [cv: ContextViewer]
RETURNS [ctx: Context] ~ {
base: Context ~ ViewerPrivate.CreateContext[ViewerPrivate.Screen.FIRST];
vc: ViewerContext ~ NEW [ViewerContextPrivate ¬ [cv, base, base.class]];
IF
NOT cv.scbKnown
THEN {
br: Rectangle ~ ImagerBackdoor.GetBounds[base];
cv.scb ¬ [Real.Ceiling[br.x], Real.Ceiling[br.y], Real.Floor[br.x+br.w], Real.Floor[br.y+br.h]];
cv.scbKnown ¬ TRUE};
ctx ¬ NEW [Imager.ContextRep ¬ [class: vcClass, state: NIL, data: vc]];
cv.ctxs ¬ CONS[ctx, cv.ctxs];
RETURN};
QuaViewerContext:
PUBLIC
PROC [c: Context]
RETURNS [MaybeContextViewer] ~ {
IF c.class=vcClass
AND c.data#
NIL
THEN
WITH c.data
SELECT
FROM
x: ViewerContext => RETURN [[TRUE, x.cv]];
ENDCASE => NULL;
RETURN [[FALSE, NIL]]};
SetCursor:
PUBLIC
PROC [cv: ContextViewer, ct: ViewerClasses.CursorType] ~ {
cv.inner.class.cursor ¬ ct;
RETURN};
CVDestroy:
PROC [self: Viewer]
--ViewerClasses.DestroyProc-- ~ {
cv: ContextViewer ~ NARROW[self.data];
Destroy[cv];
RETURN};
Destroy:
PUBLIC
PROC [cv: ContextViewer] ~ {
IF
NOT cv.destroyed
THEN {
cv.destroyed ¬ TRUE;
IF NOT cv.ctr.destroyed THEN TRUSTED {Process.Detach[FORK ViewerOps.DestroyViewer[cv.ctr]]};
IF cv.NoteDestruction#NIL THEN cv.NoteDestruction[cv.clientData];
};
RETURN};
CreateMenuPane:
PROC [cv: ContextViewer]
RETURNS [menuPane: Viewer] ~ {
aligner, destroyer: Viewer;
menuPane ¬ Ctrs.Create[$VanillaMJSContainer, [parent: cv.ctr, ww: cv.ctr.cw, wh: menuHeight, border: FALSE, scrollable: FALSE], FALSE];
aligner ¬ alignerClass.Instantiate[viewerInfo: [parent: menuPane, name: "Align", border: FALSE], instanceData: cv, paint: FALSE];
destroyer ¬ destroyerClass.Instantiate[viewerInfo: [parent: menuPane, name: "Destroy", wx: aligner.ww+menuSep, border: FALSE], instanceData: cv, paint: FALSE];
cv.sizeButton ¬ sizeClass.Instantiate[viewerInfo: [parent: menuPane, name: "Size", wx: destroyer.wx+destroyer.ww+menuSep, border: FALSE], instanceData: cv, image: ImageForSize[cv.size], paint: FALSE];
cv.scrollCtl ¬ (IF cv.scrollable THEN toUnscrollableClass ELSE toScrollableClass).Instantiate[viewerInfo: [parent: menuPane, wx: cv.sizeButton.wx+cv.sizeButton.ww+menuSep, border: FALSE], instanceData: cv, paint: FALSE];
cv.menuWidth ¬ cv.scrollCtl.wx + cv.scrollCtl.ww;
RETURN};
ImageForSize:
PROC [size:
VECI]
RETURNS [
PUB.Image]
~ {RETURN PUB.ImageForRope[IO.PutFR["Size: [w: %g, h: %g]", [integer[size.x]], [integer[size.y]] ]]};
CVPop:
PROC [view, instanceData, classData, key:
REF
ANY]
--PUB.PopUpButtonProc-- ~ {
cv: ContextViewer ~ NARROW[instanceData];
WITH key
SELECT
FROM
a:
ATOM =>
SELECT a
FROM
$Destroy => Destroy[cv];
$SetSize => {
seln: ROPE ~ ViewerTools.GetSelectionContents[];
in: IO.STREAM ~ IO.RIS[seln];
newSize: RECORD [x, y: INT] ¬ [0, 0];
{ENABLE IO.Error, IO.EndOfStream => GOTO Bitch;
newSize.x ¬ in.GetInt[];
newSize.y ¬ in.GetInt[];
IF NOT (newSize.x IN [5..5000] AND newSize.y IN [5..5000] ) THEN GOTO Bitch;
EXITS Bitch => {
MessageWindow.Append["Selection should be two whitespace-separated integers (of reasonable value)", TRUE];
RETURN};
};
in.Close[];
SetIdealSize[cv, [newSize.x, newSize.y]];
};
$FitSize => {
SetIdealSize[cv, [cv.inner.cw, cv.inner.ch]];
};
$ToScrollable => {
cv.scrollable ¬ TRUE;
PUB.AmbushInstance[cv.scrollCtl, toUnscrollableClass]};
$ToUnscrollable => {
cv.scrollable ¬ FALSE;
PUB.AmbushInstance[cv.scrollCtl, toScrollableClass]};
ENDCASE => ERROR;
lora:
LORA => {
h, v: REAL ¬ -1.0;
Alignit:
PROC ~ {
IF h>=0.0 THEN cv.i2w.x ¬ Real.Round[h * (cv.vcs.x-cv.size.x)];
IF v>=0.0 THEN cv.i2w.y ¬ Real.Round[v * (cv.vcs.y-cv.size.y)];
cv.i2s ¬ ViAdd[cv.i2w, cv.w2s];
cv.needClear ¬ TRUE;
IF cv.NoteChange#NIL THEN cv.NoteChange[cv.clientData, cv.i2w, cv.w2s, cv.vcs, cv.size];
InvalidateEm[cv];
RETURN};
FOR l:
LORA ¬ lora, l.rest
WHILE l#
NIL
DO
SELECT l.first
FROM
$Left => h ¬ 0.0;
$HCenter => h ¬ 0.5;
$Right => h ¬ 1.0;
$Bottom => v ¬ 0.0;
$VCenter => v ¬ 0.5;
$Top => v ¬ 1.0;
ENDCASE => ERROR;
ENDLOOP;
ViewerLocks.CallUnderWriteLock[Alignit, cv.inner];
RETURN};
ENDCASE => ERROR;
};
NestedEnter: ERROR ~ CODE;
Enter:
PROC [vc: ViewerContext] ~ {
cv: ContextViewer ~ vc.cv;
destroy: BOOL ¬ FALSE;
GetIn:
ENTRY
PROC [cv: ContextViewer] ~ {
ENABLE UNWIND => NULL;
IF cv.in AND cv.cIn=vc THEN RETURN WITH ERROR NestedEnter;
cv.wantIn ¬ cv.wantIn.SUCC;
Wait[];
cv.cIn ¬ vc;
RETURN};
Wait:
INTERNAL
PROC ~ {
ENABLE UNWIND => cv.wantIn ¬ cv.wantIn.PRED;
BROADCAST cv.change;
UNTIL cv.destroyed
OR cv.ctr.destroyed
OR cv.in
AND cv.cIn=
NIL
AND (cv.stayIn#
NIL
OR
NOT cv.wantOut)
DO
WAIT cv.change;
ENDLOOP;
destroy ¬ cv.destroyed OR cv.ctr.destroyed;
RETURN};
GetIn[cv];
IF destroy
AND
NOT vc.destroyed
THEN {vc.destroyed ¬ TRUE; vc.base.SetNoImage[TRUE]};
IF
NOT vc.valid
THEN {
xmin: INTEGER ~ MAX[cv.w2s.x, cv.i2s.x];
ymin: INTEGER ~ MAX[cv.w2s.y, cv.i2s.y];
xmax: INTEGER ~ MIN[cv.w2s.x+cv.vcs.x, cv.i2s.x+cv.size.x];
ymax: INTEGER ~ MIN[cv.w2s.y+cv.vcs.y, cv.i2s.y+cv.size.y];
cp: VEC ~ vc.baseClass.GetCP[vc.base, FALSE];
ImagerBackdoor.ViewReset[vc.base];
ImagerBackdoor.ViewClipRectangleI[vc.base, xmin, ymin, MAX[xmax-xmin, 0], MAX[ymax-ymin, 0]];
ImagerBackdoor.ViewTranslateI[vc.base, cv.i2s.x, cv.i2s.y];
FOR cr: ClipList ¬ vc.clipList, cr.rest
WHILE cr#
NIL
DO
WITH cr.first
SELECT
FROM
q: rect ClipItem => vc.baseClass.ViewClipRectangleI[vc.base, q.ri.x, q.ri.y, q.ri.w, q.ri.h, cr.first.exclude];
q: outline ClipItem => {
ClipPath: ImagerPath.PathProc ~ {
ImagerPath.MapOutline[q.o, moveTo, lineTo, curveTo, conicTo, arcTo];
RETURN};
vc.baseClass.ViewClip[vc.base, ClipPath, q.oddWrap, cr.first.exclude]};
ENDCASE => ERROR;
ENDLOOP;
ImagerBackdoor.ViewTranslateI[vc.base, vc.viewToIdeal.x, vc.viewToIdeal.y];
vc.baseClass.SetXY[vc.base, cp];
vc.valid ¬ TRUE};
RETURN};
Exit:
ENTRY
PROC [vc: ViewerContext] ~ {
ENABLE UNWIND => NULL;
IF vc.cv.cIn # vc THEN ERROR;
vc.cv.wantIn ¬ vc.cv.wantIn.PRED;
vc.cv.cIn ¬ NIL;
BROADCAST vc.cv.change;
RETURN};
PaintDriver:
PROC [cv: ContextViewer] ~ {
Test:
ENTRY
PROC
RETURNS [
BOOL] ~ {
ENABLE UNWIND => NULL;
UNTIL cv.destroyed OR cv.ctr.destroyed OR (cv.needClear OR cv.wantIn>0) AND NOT cv.ctr.iconic DO WAIT cv.change ENDLOOP;
RETURN [cv.destroyed OR cv.ctr.destroyed]};
exit: BOOL;
DO
ENABLE
ABORTED =>
CONTINUE;
exit ¬ Test[];
IF exit THEN EXIT;
ViewerOps.PaintViewer[cv.inner, client, FALSE];
ENDLOOP;
RETURN};
Paint:
ENTRY
PROC [self: Viewer, context: Context, whatChanged:
REF, clear:
BOOL]
RETURNS [quit:
BOOL ¬
FALSE]
--ViewerClasses.PaintProc-- ~ {
ENABLE UNWIND => {cv: ContextViewer ~ NARROW[self.data]; cv.wantOut ¬ cv.in ¬ FALSE};
cv: ContextViewer ~ NARROW[self.data];
wts: VECI;
IF self.destroyed THEN RETURN;
IF cv.needClear
AND
NOT clear
THEN {
context.SetColor[Imager.white];
context.MaskRectangleI[0, 0, self.cw, self.ch];
clear ¬ TRUE};
IF clear
THEN {
cv.needClear ¬ FALSE;
IF cv.NoteClear#NIL THEN cv.NoteClear[cv.clientData]};
[wts.x, wts.y] ¬ ViewerOps.UserToScreenCoords[self, 0, 0];
IF cv.w2s#wts
OR cv.vcs#[self.cw, self.ch]
THEN {
cv.w2s ¬ wts;
cv.i2s ¬ ViAdd[cv.i2w, cv.w2s];
cv.vcs ¬ [self.cw, self.ch];
IF cv.NoteChange#NIL THEN cv.NoteChange[cv.clientData, cv.i2w, cv.w2s, cv.vcs, cv.size];
InvalidateEm[cv]};
IF cv.wantIn>0
THEN
TRUSTED {
hold: CONDITION;
Process.InitializeCondition[@hold, Process.MsecToTicks[msHold]];
Process.EnableAborts[@hold];
cv.in ¬ TRUE;
BROADCAST cv.change;
WAIT hold;
cv.wantOut ¬ TRUE;
UNTIL cv.destroyed OR cv.cIn=NIL AND cv.stayIn=NIL DO WAIT cv.change ENDLOOP;
cv.wantOut ¬ cv.in ¬ FALSE};
RETURN};
Scroll:
PROC [self: Viewer, op: ViewerClasses.ScrollOp, amount:
INTEGER, shift, control:
BOOL ¬
FALSE]
RETURNS [top, bottom:
INTEGER ¬
LAST[
INTEGER]]
--ViewerClasses.ScrollProc-- ~ {
cv: ContextViewer ~ NARROW[self.data];
UpdateY:
PROC ~ {
cv.i2s ¬ ViAdd[cv.i2w, cv.w2s];
cv.needClear ¬ TRUE;
IF cv.NoteChange#NIL THEN cv.NoteChange[cv.clientData, cv.i2w, cv.w2s, cv.vcs, cv.size];
InvalidateEm[cv];
RETURN};
IF op#query
AND
NOT cv.scrollable
THEN {
MessageWindow.Append["This viewer is not currently scrollable.", TRUE];
RETURN};
SELECT op
FROM
query => {
botr: REAL ~ REAL[cv.size.y+cv.i2w.y]/cv.size.y;
topr: REAL ~ REAL[cv.size.y+cv.i2w.y-cv.vcs.y]/cv.size.y;
RETURN [MIN[MAX[Real.Round[topr*100.0], 0], 100], MIN[MAX[Real.Round[botr*100.0], 0], 100] ]};
up, down => cv.i2w.y ¬ cv.i2w.y + amount * (IF op=up THEN 1 ELSE -1);
thumb => cv.i2w.y ¬ Real.Round[(amount/100.0 - 1.0)*cv.size.y] + cv.vcs.y;
ENDCASE => ERROR;
ViewerLocks.CallUnderWriteLock[UpdateY, self];
RETURN};
HScroll:
PROC [self: Viewer, op: ViewerClasses.HScrollOp, amount:
INTEGER, shift, control:
BOOL ¬
FALSE]
RETURNS [left, right:
INTEGER ¬
LAST[
INTEGER]]
--ViewerClasses.HScrollProc-- ~ {
cv: ContextViewer ~ NARROW[self.data];
UpdateX:
PROC ~ {
cv.i2s ¬ ViAdd[cv.i2w, cv.w2s];
cv.needClear ¬ TRUE;
IF cv.NoteChange#NIL THEN cv.NoteChange[cv.clientData, cv.i2w, cv.w2s, cv.vcs, cv.size];
InvalidateEm[cv];
RETURN};
IF op#query
AND
NOT cv.scrollable
THEN {
MessageWindow.Append["This viewer is not currently scrollable.", TRUE];
RETURN};
SELECT op
FROM
query => {
leftr: REAL ~ REAL[-cv.i2w.x]/cv.size.x;
rightr: REAL ~ REAL[cv.vcs.x-cv.i2w.x]/cv.size.x;
RETURN [MIN[MAX[Real.Round[leftr*100.0], 0], 100], MIN[MAX[Real.Round[rightr*100.0], 0], 100] ]};
left, right => cv.i2w.x ¬ cv.i2w.x + amount * (IF op=right THEN 1 ELSE -1);
thumb => cv.i2w.x ¬ Real.Round[(-amount/100.0)*cv.size.y];
ENDCASE => ERROR;
ViewerLocks.CallUnderWriteLock[UpdateX, self];
RETURN};
InvalidateEm:
--Viewer INTERNAL--
PROC [cv: ContextViewer] ~ {
cv.in ¬ cv.in;
FOR cl: ContextList ¬ cv.ctxs, cl.rest
WHILE cl#
NIL
DO
vc: ViewerContext ~ NARROW[cl.first.data];
vc.valid ¬ FALSE;
ENDLOOP;
cv.ctxs ¬ NIL;
RETURN};
Notify: ViewerClasses.NotifyProc ~ {
cv: ContextViewer ~ NARROW[self.data];
IF NOT cv.focused THEN InputFocus.SetInputFocus[self];
RETURN};
CVModify:
PROC [self: Viewer, change: ViewerClasses.ModifyAction] ~ {
cv: ContextViewer ~ NARROW[self.data];
SELECT change
FROM
set, pop => cv.focused ¬ TRUE;
kill, push => cv.focused ¬ FALSE;
ENDCASE => ERROR;
RETURN};
VCSave:
PROC [context: Context, all:
BOOL]
RETURNS [
REF] ~ {
vc: ViewerContext ~ NARROW[context.data];
ans: REF;
Enter[vc]; {ENABLE UNWIND => Exit[vc];
ans ¬ vc.baseClass.Save[vc.base, all]};
Exit[vc]; RETURN [ans]};
VCRestore:
PROC [context: Context, ref:
REF] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.Restore[vc.base, ref]};
Exit[vc]; RETURN};
VCSetInt:
PROC [context: Context, key: ImagerBackdoor.IntKey, val:
INT] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetInt[vc.base, key, val]};
Exit[vc]; RETURN};
VCSetReal:
PROC [context: Context, key: ImagerBackdoor.RealKey, val:
REAL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetReal[vc.base, key, val]};
Exit[vc]; RETURN};
VCSetT:
PROC [context: Context, m: Xfm] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetT[vc.base, m]};
Exit[vc]; RETURN};
VCSetFont:
PROC [context: Context, font: Imager.Font] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetFont[vc.base, font]};
Exit[vc]; RETURN};
VCSetColor:
PROC [context: Context, color: Imager.Color] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetColor[vc.base, color]};
Exit[vc]; RETURN};
VCSetClipper:
PROC [context: Context, clipper: ImagerBackdoor.Clipper] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetClipper[vc.base, clipper]};
Exit[vc]; RETURN};
VCGetInt:
PROC [context: Context, key: ImagerBackdoor.IntKey]
RETURNS [
INT] ~ {
vc: ViewerContext ~ NARROW[context.data];
ans: INT;
Enter[vc]; {ENABLE UNWIND => Exit[vc];
ans ¬ vc.baseClass.GetInt[vc.base, key]};
Exit[vc]; RETURN [ans]};
VCGetReal:
PROC [context: Context, key: ImagerBackdoor.RealKey]
RETURNS [
REAL] ~ {
vc: ViewerContext ~ NARROW[context.data];
ans: REAL;
Enter[vc]; {ENABLE UNWIND => Exit[vc];
ans ¬ vc.baseClass.GetReal[vc.base, key]};
Exit[vc]; RETURN [ans]};
VCGetT:
PROC [context: Context]
RETURNS [Xfm] ~ {
vc: ViewerContext ~ NARROW[context.data];
ans: Xfm;
Enter[vc]; {ENABLE UNWIND => Exit[vc];
ans ¬ vc.baseClass.GetT[vc.base]};
Exit[vc]; RETURN [ans]};
VCGetFont:
PROC [context: Context]
RETURNS [Imager.Font] ~ {
vc: ViewerContext ~ NARROW[context.data];
ans: Imager.Font;
Enter[vc]; {ENABLE UNWIND => Exit[vc];
ans ¬ vc.baseClass.GetFont[vc.base]};
Exit[vc]; RETURN [ans]};
VCGetColor:
PROC [context: Context]
RETURNS [Imager.Color] ~ {
vc: ViewerContext ~ NARROW[context.data];
ans: Imager.Color;
Enter[vc]; {ENABLE UNWIND => Exit[vc];
ans ¬ vc.baseClass.GetColor[vc.base]};
Exit[vc]; RETURN [ans]};
VCGetClipper:
PROC [context: Context]
RETURNS [ImagerBackdoor.Clipper] ~ {
vc: ViewerContext ~ NARROW[context.data];
ans: ImagerBackdoor.Clipper;
Enter[vc]; {ENABLE UNWIND => Exit[vc];
ans ¬ vc.baseClass.GetClipper[vc.base]};
Exit[vc]; RETURN [ans]};
VCConcatT:
PROC [context: Context, m: Xfm] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.ConcatT[vc.base, m]};
Exit[vc]; RETURN};
VCScale2T:
PROC [context: Context, s:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.Scale2T[vc.base, s]};
Exit[vc]; RETURN};
VCRotateT:
PROC [context: Context, a:
REAL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.RotateT[vc.base, a]};
Exit[vc]; RETURN};
VCTranslateT:
PROC [context: Context, t:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.TranslateT[vc.base, t]};
Exit[vc]; RETURN};
VCMove:
PROC [context: Context, rounded:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.Move[vc.base, rounded]};
Exit[vc]; RETURN};
VCSetXY:
PROC [context: Context, p:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetXY[vc.base, p]};
Exit[vc]; RETURN};
VCSetXYRel:
PROC [context: Context, v:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetXYRel[vc.base, v]};
Exit[vc]; RETURN};
VCGetCP:
PROC [context: Context, rounded:
BOOL]
RETURNS [ans:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
ans ¬ vc.baseClass.GetCP[vc.base, rounded]};
Exit[vc]; RETURN};
VCStartUnderline:
PROC [context: Context] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.StartUnderline[vc.base]};
Exit[vc]; RETURN};
VCMaskUnderline:
PROC [context: Context, dy, h:
REAL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.MaskUnderline[vc.base, dy, h]};
Exit[vc]; RETURN};
VCCorrectMask:
PROC [context: Context] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.CorrectMask[vc.base]};
Exit[vc]; RETURN};
VCCorrectSpace:
PROC [context: Context, v:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.CorrectSpace[vc.base, v]};
Exit[vc]; RETURN};
VCSpace:
PROC [context: Context, x:
REAL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.Space[vc.base, x]};
Exit[vc]; RETURN};
VCSetCorrectMeasure:
PROC [context: Context, v:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetCorrectMeasure[vc.base, v]};
Exit[vc]; RETURN};
VCSetCorrectTolerance:
PROC [context: Context, v:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetCorrectTolerance[vc.base, v]};
Exit[vc]; RETURN};
VCCorrect:
PROC [context: Context, action:
PROC] ~ {
vc: ViewerContext ~ NARROW[context.data];
vc.baseClass.Correct[vc.base, action];
RETURN};
VCDontCorrect:
PROC [context: Context, action:
PROC, saveCP:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
IF saveCP
THEN {
cp: VEC;
Enter[vc]; {ENABLE UNWIND => Exit[vc];
cp ¬ vc.baseClass.GetCP[vc.base, FALSE]};
Exit[vc];
vc.baseClass.DontCorrect[vc.base, action, saveCP];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetXY[vc.base, cp]};
Exit[vc]}
ELSE vc.baseClass.DontCorrect[vc.base, action, saveCP];
RETURN};
VCSetGray:
PROC [context: Context, f:
REAL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetGray[vc.base, f]};
Exit[vc]; RETURN};
VCSetSampledColor:
PROC [context: Context, pa: PixelArray, m: Xfm, colorOperator: ColorOperator] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetSampledColor[vc.base, pa, m, colorOperator]};
Exit[vc]; RETURN};
VCSetSampledBlack:
PROC [context: Context, pa: PixelArray, m: Xfm, clear:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.SetSampledBlack[vc.base, pa, m, clear]};
Exit[vc]; RETURN};
VCClip:
PROC [context: Context, path: PathProc, oddWrap:
BOOL, exclude:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.Clip[vc.base, path, oddWrap, exclude]};
Exit[vc]; RETURN};
VCClipRectangle:
PROC [context: Context, r: Imager.Rectangle, exclude:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.ClipRectangle[vc.base, r, exclude]};
Exit[vc]; RETURN};
VCClipRectangleI:
PROC [context: Context, x, y, w, h:
INTEGER, exclude:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.ClipRectangleI[vc.base, x, y, w, h, exclude]};
Exit[vc]; RETURN};
VCShow:
PROC [context: Context, string: XStringProc, xrel:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.Show[vc.base, string, xrel]};
Exit[vc]; RETURN};
VCShowBackward:
PROC [context: Context, string: XStringProc] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.ShowBackward[vc.base, string]};
Exit[vc]; RETURN};
VCMaskFill:
PROC [context: Context, path: PathProc, oddWrap:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.MaskFill[vc.base, path, oddWrap]};
Exit[vc]; RETURN};
VCMaskRectangle:
PROC [context: Context, r: Imager.Rectangle] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.MaskRectangle[vc.base, r]};
Exit[vc]; RETURN};
VCMaskStroke:
PROC [context: Context, path: PathProc, closed:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.MaskStroke[vc.base, path, closed]};
Exit[vc]; RETURN};
VCMaskPixel:
PROC [context: Context, pa: PixelArray] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.MaskPixel[vc.base, pa]};
Exit[vc]; RETURN};
VCShowAndFixedXRel:
PROC [context: Context, string: XStringProc, x:
REAL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.ShowAndFixedXRel[vc.base, string, x]};
Exit[vc]; RETURN};
VCShowText:
PROC [context: Context, text:
REF
READONLY
TEXT, start, len:
NAT, xrel:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.ShowText[vc.base, text, start, len, xrel]};
Exit[vc]; RETURN};
VCMaskRectangleI:
PROC [context: Context, x, y, w, h:
INTEGER] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.MaskRectangleI[vc.base, x, y, w, h]};
Exit[vc]; RETURN};
VCMaskVector:
PROC [context: Context, p1, p2:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.MaskVector[vc.base, p1, p2]};
Exit[vc]; RETURN};
VCMaskDashedStroke:
PROC [context: Context, path: PathProc, patternLen:
NAT, pattern:
PROC [
NAT]
RETURNS [
REAL], offset, length:
REAL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.MaskDashedStroke[vc.base, path, patternLen, pattern, offset, length]};
Exit[vc]; RETURN};
VCMaskBitmap:
PROC [context: Context, bitmap: SampleMap, referencePoint:
SF.Vec, scanMode: ScanMode, position:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.MaskBitmap[vc.base, bitmap, referencePoint, scanMode, position]};
Exit[vc]; RETURN};
VCDrawBitmap:
PROC [context: Context, bitmap: SampleMap, referencePoint:
SF.Vec, scanMode: ScanMode, position:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.DrawBitmap[vc.base, bitmap, referencePoint, scanMode, position]};
Exit[vc]; RETURN};
VCDrawPixels:
PROC [context: Context, pixelMap: PixelMap, colorOperator: ColorOperator, referencePoint:
SF.Vec, scanMode: ScanMode, position:
VEC] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.DrawPixels[vc.base, pixelMap, colorOperator, referencePoint, scanMode, position]};
Exit[vc]; RETURN};
VCDoIfVisible:
PROC [context: Context, r: Rectangle, action:
PROC] ~ {
vc: ViewerContext ~ NARROW[context.data];
vc.baseClass.DoIfVisible[vc.base, r, action];
RETURN};
VCDoWithBuffer:
PROC [context: Context, action:
PROC, x, y, w, h:
INTEGER, backgroundColor: Color] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
AddStay[vc.cv, [vc, doWithBuffer, NIL, [x, y, w, h]]]};
Exit[vc];
vc.baseClass.DoWithBuffer[vc.base, action, x, y, w, h, backgroundColor];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
RemStay[vc.cv, [vc, doWithBuffer, NIL, [x, y, w, h]]]};
Exit[vc]; RETURN};
VCDrawObject:
PROC [context: Context, object: Imager.Object, position:
VEC, interactive:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.DrawObject[vc.base, object, position, interactive]};
Exit[vc]; RETURN};
VCGetBounds:
PROC [context: Context]
RETURNS [Rectangle] ~ {
vc: ViewerContext ~ NARROW[context.data];
RETURN vc.baseClass.GetBounds[vc.base]};
VCViewReset:
PROC [context: Context] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.viewToIdeal ¬ [0, 0];
vc.clipList ¬ NIL;
vc.valid ¬ FALSE};
Exit[vc]; RETURN};
VCViewTranslateI:
PROC [context: Context, x, y:
INTEGER] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
cp: VEC ~ vc.baseClass.GetCP[vc.base, FALSE];
vc.viewToIdeal ¬ ViAdd[vc.viewToIdeal, [x, y]];
vc.baseClass.ViewTranslateI[vc.base, x, y];
vc.baseClass.SetXY[vc.base, cp]};
Exit[vc]; RETURN};
VCViewClip:
PROC [context: Context, path: PathProc, oddWrap:
BOOL, exclude:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
m: Xfm ~ IT.Translate[[vc.viewToIdeal.x, vc.viewToIdeal.y]];
o: Outline ~ ImagerPath.OutlineFromPath[path, oddWrap, m];
vc.clipList ¬ CONS[[exclude, outline[o, oddWrap]], vc.clipList];
vc.baseClass.ViewClip[vc.base, path, oddWrap, exclude]};
Exit[vc]; RETURN};
VCViewClipRectangleI:
PROC [context: Context, x, y, w, h:
INTEGER, exclude:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.clipList ¬ CONS[[exclude, rect[[x+vc.viewToIdeal.x, y+vc.viewToIdeal.y, w, h]]], vc.clipList];
vc.baseClass.ViewClipRectangleI[vc.base, x, y, w, h, exclude]};
Exit[vc]; RETURN};
VCGetTransformation:
PROC [context: Context, from, to: ImagerBackdoor.CoordSys]
RETURNS [Xfm] ~ {
vc: ViewerContext ~ NARROW[context.data];
RETURN vc.baseClass.GetTransformation[vc.base, from, to]};
VCMoveViewRectangle:
PROC [context: Context, width, height, fromX, fromY, toX, toY:
INTEGER] ~ {
vc: ViewerContext ~ NARROW[context.data];
cv: ContextViewer ~ vc.cv;
Enter[vc]; {ENABLE UNWIND => Exit[vc];
bClipIdeal: BoxI ~ [0, 0, cv.size.x, cv.size.y];
bClipViewer: BoxI ~ BiOffset[[0, 0, cv.vcs.x, cv.vcs.y], [-cv.i2w.x, -cv.i2w.y]];
bClipScreen: BoxI ~ BiOffset[cv.scb, [-cv.i2s.x, -cv.i2s.y]];
bClip: BoxI ~ BiOffset[BiIntersect[BiIntersect[bClipIdeal, bClipViewer], bClipScreen], [-vc.viewToIdeal.x, -vc.viewToIdeal.y]];
bFrom: BoxI ¬ BiIntersect[bClip, [fromX, fromY, fromX+width, fromY+height]];
bTo: BoxI ¬ BiIntersect[bClip, [toX, toY, toX+width, toY+height]];
toW: INTEGER ¬ bTo.xmax - bTo.xmin;
toH: INTEGER ¬ bTo.ymax - bTo.ymin;
dx: INTEGER ¬ toX - fromX;
dy: INTEGER ¬ toY - fromY;
bFrom ¬ BiIntersect[bFrom, BiOffset[bTo, [-dx, -dy]]];
{fromW: INTEGER ¬ bFrom.xmax - bFrom.xmin;
fromH: INTEGER ¬ bFrom.ymax - bFrom.ymin;
IF fromW>0 AND fromH>0 THEN vc.baseClass.MoveViewRectangle[vc.base, fromW, fromH, bFrom.xmin, bFrom.ymin, bFrom.xmin+dx, bFrom.ymin+dy];
IF toW>0
AND toH>0
AND (toW#fromW
OR toH#fromH)
THEN {
dun: BoxI ~ BiOffset[bFrom, [dx, dy]];
MarkForgotten:
PROC ~ {
midY: INTEGER ~ dun.ymin;
midH: INTEGER ~ fromH;
vc.baseClass.SetT[vc.base, idXfm];
vc.baseClass.SetColor[vc.base, forgottenColor];
IF dun.ymin > bTo.ymin THEN vc.baseClass.MaskRectangleI[vc.base, bTo.xmin, bTo.ymin, toW, dun.ymin - bTo.ymin];
IF bTo.ymax > dun.ymax THEN vc.baseClass.MaskRectangleI[vc.base, bTo.xmin, dun.ymax, toW, bTo.ymax - dun.ymax];
IF midH>0
THEN {
IF dun.xmin > bTo.xmin THEN vc.baseClass.MaskRectangleI[vc.base, bTo.xmin, midY, dun.xmin - bTo.xmin, midH];
IF bTo.xmax > dun.xmax THEN vc.baseClass.MaskRectangleI[vc.base, dun.xmax, midY, bTo.xmax - dun.xmax, midH];
};
RETURN};
vc.base.DoSave[MarkForgotten];
width ¬ width};
}};
Exit[vc]; RETURN};
forgottenColor: Color ¬ ImagerColor.ColorFromRGB[[1, 0, 0]];
VCTestViewRectangle:
PROC [context: Context, x, y, w, h:
INTEGER]
RETURNS [ImagerBackdoor.Visibility] ~ {
vc: ViewerContext ~ NARROW[context.data];
RETURN vc.baseClass.TestViewRectangle[vc.base, x, y, w, h]};
VCGetBufferColorOperator:
PROC [context: Context]
RETURNS [ColorOperator] ~ {
vc: ViewerContext ~ NARROW[context.data];
RETURN vc.baseClass.GetBufferColorOperator[vc.base]};
VCSaveBuffer:
PROC [context: Context, id:
ATOM, path: PathProc, oddWrap:
BOOL] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
AddStay[vc.cv, [vc, savedBuffer, id]];
vc.baseClass.SaveBuffer[vc.base, id, path, oddWrap]};
Exit[vc]; RETURN};
VCRestoreBuffer:
PROC [context: Context, id:
ATOM] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
vc.baseClass.RestoreBuffer[vc.base, id]};
Exit[vc]; RETURN};
VCDiscardBuffer:
PROC [context: Context, id:
ATOM] ~ {
vc: ViewerContext ~ NARROW[context.data];
Enter[vc]; {ENABLE UNWIND => Exit[vc];
RemStay[vc.cv, [vc, savedBuffer, id]];
vc.baseClass.DiscardBuffer[vc.base, id]};
Exit[vc]; RETURN};
AddStay:
--Viewer INTERNAL--
PROC [cv: ContextViewer, stay: StayDef]
~ {cv.stayIn ¬ CONS[[stay, IF stay.name#NIL THEN Atom.GetPName[stay.name] ELSE NIL], cv.stayIn]};
RemStay:
--Viewer INTERNAL--
PROC [cv: ContextViewer, stay: StayDef] ~ {
last: StayList ¬ NIL;
FOR this: StayList ¬ cv.stayIn, this.rest
WHILE this#
NIL
DO
IF this.first.def = stay
THEN {
IF last=NIL THEN cv.stayIn ¬ this.rest ELSE last.rest ¬ this.rest;
RETURN};
last ¬ this; ENDLOOP;
ERROR};
BiIntersect:
PROC [a, b: BoxI]
RETURNS [BoxI]
~ {
xmin: INTEGER ~ MAX[a.xmin, b.xmin];
ymin: INTEGER ~ MAX[a.ymin, b.ymin];
RETURN[[xmin, ymin, MAX[xmin, MIN[a.xmax, b.xmax]], MAX[ymin, MIN[a.ymax, b.ymax]]]]};
BiOffset:
PROC [b: BoxI, o:
VECI]
RETURNS [BoxI]
~ {RETURN[[b.xmin+o.x, b.ymin+o.y, b.xmax+o.x, b.ymax+o.y]]};
ViAdd:
PROC [a, b:
VECI]
RETURNS [
VECI]
~ INLINE {RETURN [[a.x+b.x, a.y+b.y]]};
Ctrs.RegisterClass[ctrFlavor, ctrClass];
END.