mShowDimeImpl.mesa
Copyright Ó 1992 by Xerox Corporation. All rights reserved.
Greene, June 1, 1990 8:42 pm PDT
Chauser, June 2, 1992 2:42 pm PDT
DIRECTORY
Browser2D,
BiScrollers,
BiScrollersExtras,
Containers,
MJSContainers,
Geom2D,
Imager,
ImagerPath,
PreemptablePaintProcs,
Process,
QuadTree,
Real,
Rope,
TIPUser,
Vector,
ViewerClasses,
ViewerOps,
ViewerTools;
Browser2DImpl: CEDAR PROGRAM
IMPORTS BiScrollers, BiScrollersExtras, Imager, ImagerPath, MJSContainers, Geom2D, PreemptablePaintProcs, Process, QuadTree, Rope, TIPUser, Vector, ViewerOps, ViewerTools EXPORTS Browser2D =
BEGIN OPEN Browser2D;
paintEnumerateQuanta: CARD ¬ 10;
Handle: TYPE = REF BrowserHandleRec;
BrowserHandleRec: PUBLIC TYPE = RECORD[
container: Containers.Container,
universe: BoundingBox,
selectionDistance: REAL,
biscroller: BiScrollers.BiScroller ¬ NIL,
drawingContext: PreemptablePaintProcs.LockedContext ¬ PreemptablePaintProcs.NilLockedContext[],
messageWindow: ViewerClasses.Viewer,
mousePosition: BiScrollers.ClientCoords ¬ NIL,
clientSelected: LIST OF Item,
userSelected: LIST OF Item,
tree: QuadTree.QT ¬ NIL,
data: REF ANY,
destroy: DestroyProc
];
SpecialRequest: TYPE = REF SpecialRequestRec;
SpecialRequestRec: TYPE = RECORD [
item: Item,
how: Instruction
];
Paint: ViewerClasses.PaintProc = {
my: Handle ¬ NARROW[bSstyle.ClientDataOf[NARROW[self.data]]];
WITH whatChanged SELECT FROM
singleItem: SpecialRequest =>
IF singleItem.item.class.paint = NIL THEN
DefaultPaint[singleItem.item, my.data, context, NIL, singleItem.how]
ELSE
singleItem.item.class.paint[singleItem.item, my.data, context, NIL, singleItem.how];
lc: PreemptablePaintProcs.LockedContext => {
IF my.drawingContext # lc THEN {
PreemptablePaintProcs.AbortContext[lc];
RETURN;
};
[] ¬ PreemptablePaintProcs.PaintWithoutLocks[self, context, whatChanged, clear, ForkedPainter];
};
ENDCASE => {
PreemptablePaintProcs.AbortContext[my.drawingContext];
my.drawingContext ¬ PreemptablePaintProcs.PaintWithoutLocks[self, context, whatChanged, clear, ForkedPainter];
};
};
ForkedPainter: PreemptablePaintProcs.UnlockedPaintProc = {
my: Handle ¬ NARROW[bSstyle.ClientDataOf[NARROW[self.data]]];
PerItem: QuadTree.PerItemProc ~ {
browserItem: Item ¬ NARROW[item.data];
UnderLock: PreemptablePaintProcs.LockedContextActionProc ~ {
IF browserItem.class.paint = NIL THEN DefaultPaint[browserItem, my.data, context, zip, normal]
ELSE browserItem.class.paint[browserItem, my.data, context, zip, normal];
};
PreemptablePaintProcs.DoUnderLock[lc, UnderLock];
};
TRUSTED{Process.Detach[FORK PaintAllSelections[my]]};
Process.SetPriority[Process.priorityBackground];
QuadTree.Enumerate[my.tree, CurrentViewBox[my.biscroller], PerItem, paintEnumerateQuanta, TRUE];
PreemptablePaintProcs.AbortContext[lc];
TRUSTED{Process.Detach[FORK PaintAllSelections[my]]};
};
Notify: ViewerClasses.NotifyProc ~ {
my: Handle ¬ NARROW[bSstyle.ClientDataOf[NARROW[self.data]]];
FOR list: LIST OF REF ANY ¬ input, list.rest UNTIL list = NIL DO
WITH list.first SELECT FROM
a: ATOM => {
IF a = $UserSelect THEN {
ClearAllSelections[my];
FindNearestItemAndSelect[my];
}
ELSE IF a = $UserExtend THEN {
FindNearestItemAndSelect[my];
};
};
z: BiScrollers.ClientCoords => {
my.mousePosition ¬ z;
};
ENDCASE => ERROR;
ENDLOOP;
};
Destroy: ViewerClasses.DestroyProc ~ {
my: Handle ¬ NARROW[bSstyle.ClientDataOf[NARROW[self.data]]];
IF my.drawingContext # NIL THEN PreemptablePaintProcs.AbortContext[my.drawingContext];
IF my.destroy # NIL THEN my.destroy[my.data]; my.data ¬ NIL;
IF my.tree # NIL THEN my.tree.Destroy[]; my.tree ¬ NIL;
};
ClearAllSelections: PUBLIC PROC [browser: Handle] ~ {
ClearClientSelections[browser];
ClearUserSelections[browser];
};
ClearClientSelections: PROC [browser: Handle] ~ {
ClearList[browser, browser.clientSelected]; browser.clientSelected ¬ NIL;
};
ClearUserSelections: PROC [browser: Handle] ~ {
ClearList[browser, browser.userSelected]; browser.userSelected ¬ NIL;
};
ClearList: PROC [browser: Handle, items: LIST OF Browser2D.Item] ~ {
UNTIL items = NIL DO
item: Item ¬ items.first;
IF item.class.selectionNotify # NIL THEN item.class.selectionNotify[item, browser.data, deSelect];
ViewerOps.PaintViewer[
viewer: bSstyle.QuaViewer[browser.biscroller],
hint: client,
clearClient: FALSE,
whatChanged: NEW[SpecialRequestRec ¬ [item, deSelect]]
];
items ¬ items.rest;
ENDLOOP;
};
PaintAllSelections: PROC [browser: Handle] ~ {
PaintClientSelections[browser];
PaintUserSelections[browser];
};
PaintClientSelections: PROC [browser: Handle] ~ {
PaintList[browser, browser.clientSelected, clientSelected];
};
PaintUserSelections: PROC [browser: Handle] ~ {
PaintList[browser, browser.userSelected, userSelected];
};
PaintList: PROC [browser: Handle, items: LIST OF Browser2D.Item, selectionType: Instruction] ~ {
UNTIL items = NIL DO
item: Item ¬ items.first;
ViewerOps.PaintViewer[
viewer: bSstyle.QuaViewer[browser.biscroller],
hint: client,
clearClient: FALSE,
whatChanged: NEW[SpecialRequestRec ¬ [item, selectionType]]
];
items ¬ items.rest;
ENDLOOP;
};
FindNearestItemAndSelect: PROC [my: Handle] ~ {
box: BoundingBox ¬ [[my.mousePosition.x - my.selectionDistance, my.mousePosition.y - my.selectionDistance], [my.mousePosition.x + my.selectionDistance, my.mousePosition.y + my.selectionDistance]];
minDistance: REAL ¬ Real.LargestNumber;
minItem: Item ¬ NIL;
PerItem: QuadTree.PerItemProc ~ {
browserItem: Item ¬ NARROW[item.data];
distance: REAL ¬ IF browserItem.class.distanceTo = NIL THEN
DefaultDistanceTo[browserItem, my.data, [my.mousePosition.x, my.mousePosition.y] ]
ELSE
browserItem.class.distanceTo[browserItem, my.data, [my.mousePosition.x, my.mousePosition.y] ];
IF distance <= minDistance THEN
{minItem ¬ browserItem;
minDistance ¬ distance;
};
};
QuadTree.Enumerate[my.tree, box, PerItem];
IF minItem # NIL THEN {
ViewerOps.PaintViewer[
viewer: bSstyle.QuaViewer[my.biscroller],
hint: client,
clearClient: FALSE,
whatChanged: NEW[SpecialRequestRec ¬ [minItem, userSelected]]
];
IF minItem.class.selectionNotify # NIL THEN minItem.class.selectionNotify[minItem, my.data, userSelected];
my.userSelected ¬ CONS[minItem, my.userSelected];
};
};
Create: PUBLIC PROC [size: BoundingBox, selectionDistance: REAL, icon: ViewerClasses.IconFlavor, caption: Rope.ROPE, commonData: REF ANY, Destroy: DestroyProc ¬ NIL] RETURNS [browser: Handle] ~
{tB: ViewerClasses.Viewer;
browser ¬ NEW[BrowserHandleRec ¬ [universe: size, selectionDistance: selectionDistance, data: commonData, destroy: Destroy]];
browser.container ¬ MJSContainers.Create[
viewerFlavor: $VanillaMJSContainer,
info: [
name: caption,
icon: icon,
iconic: TRUE,
data: browser,
scrollable: FALSE
],
paint: FALSE
];
browser.biscroller ¬ bSstyle.CreateBiScroller[
class: bSclass,
info: [
parent: browser.container,
wx: 0, wy: 15,
border: FALSE,
scrollable: FALSE,
data: browser],
paint: FALSE
];
browser.tree ¬ QuadTree.Create[universe: size];
tB ¬ BiScrollers.CreateScale[[parent: browser.container, wx: 0, wy: 1, border: FALSE], browser.biscroller];
tB ¬ BiScrollers.CreateRotate[[parent: browser.container, wx: tB.wx+tB.ww+3, wy: 1, border: FALSE], browser.biscroller];
tB ¬ BiScrollers.CreateFit[[parent: browser.container, wx: tB.wx+tB.ww+3, wy: 1, border: FALSE], browser.biscroller];
tB ¬ BiScrollers.CreateReset[[parent: browser.container, wx: tB.wx+tB.ww+3, wy: 1, border: FALSE], browser.biscroller];
tB ¬ BiScrollers.CreateEdge[[parent: browser.container, wx: tB.wx+tB.ww+3, wy: 1, border: FALSE], browser.biscroller];
tB ¬ BiScrollers.CreatePrev[[parent: browser.container, wx: tB.wx+tB.ww+3, wy: 1, border: FALSE], browser.biscroller];
browser.messageWindow ¬ ViewerTools.MakeNewTextViewer[[
parent: browser.container,
wx: tB.wx+tB.ww+20, wy: 1, wh: tB.wh,
scrollable: FALSE,
border: FALSE]];
MJSContainers.ChildXBound[browser.container, browser.messageWindow];
tB ¬ bSstyle.QuaViewer[browser.biscroller];
MJSContainers.ChildXBound[browser.container, tB];
MJSContainers.ChildYBound[browser.container, tB];
ViewerOps.PaintViewer[viewer: browser.container, hint: all, clearClient: TRUE];
};
bSstyle: BiScrollers.BiScrollerStyle ¬ BiScrollers.GetStyle["Buttonless"];
bSclass: BiScrollers.BiScrollerClass ¬ bSstyle.NewBiScrollerClass[
[flavor: $Map,
extrema: Extrema,
notify: Notify,
destroy: Destroy,
paint: Paint,
tipTable: TIPUser.InstantiateNewTIPTable["CensusMap.tip"],
mayStretch: FALSE
]];
AddItem: PUBLIC PROC [browser: Handle, item: Item, paint: BOOL ¬ FALSE] ~ {
QuadTree.Insert[browser.tree, item.class.boundingBox[item, browser.data], item];
IF paint THEN ViewerOps.PaintViewer[
viewer: bSstyle.QuaViewer[browser.biscroller],
hint: client,
clearClient: FALSE,
whatChanged: item];
};
RepaintBrowser: PUBLIC PROC [browser: BrowserHandle] ~ {
ViewerOps.PaintViewer[
viewer: bSstyle.QuaViewer[browser.biscroller],
hint: client,
clearClient: FALSE];
};
SelectItem: PUBLIC PROC [browser: BrowserHandle, item: Item] ~ {
ViewerOps.PaintViewer[
viewer: bSstyle.QuaViewer[browser.biscroller],
hint: client,
clearClient: FALSE,
whatChanged: NEW[SpecialRequestRec ¬ [item, clientSelected]]
];
IF item.class.selectionNotify # NIL THEN item.class.selectionNotify[item, browser.data, clientSelected];
browser.clientSelected ¬ CONS[item, browser.clientSelected];
};
BlinkSelections: PUBLIC PROC [browser: BrowserHandle, times: INT ¬ 3, delayMSecs: INT ¬ 500] ~ {
DO
PaintList[browser, browser.clientSelected, deSelect];
PaintList[browser, browser.userSelected, deSelect];
Process.Pause[Process.MsecToTicks[delayMSecs]];
PaintAllSelections[browser];
times ¬ times - 1; IF times = 0 THEN RETURN;
Process.Pause[Process.MsecToTicks[delayMSecs]];
ENDLOOP;
};
CenterSelections: PUBLIC PROC [browser: BrowserHandle, margin: Vector.VEC, tolerance: Vector.VEC, force: BOOLEAN ¬ FALSE] RETURNS [moved: BOOLEAN] ~ {
scanSelected: LIST OF Item ¬ browser.clientSelected;
currentBox: BoundingBox ¬ CurrentViewBox[browser.biscroller];
tolerationBox, marginBox: BoundingBox;
enclosingBox: BoundingBox ¬ [[Real.LargestNumber, Real.LargestNumber], [- Real.LargestNumber, - Real.LargestNumber]];
IF scanSelected = NIL THEN RETURN[FALSE];
UNTIL scanSelected = NIL DO
item: Item ¬ scanSelected.first;
enclosingBox ¬ LeastCommonBoundingBox[enclosingBox, item.class.boundingBox[item, browser.data]];
scanSelected ¬ scanSelected.rest;
ENDLOOP;
IF NOT force THEN {
tolerationBox ¬ ExpandBox[enclosingBox, tolerance];
IF Contains[currentBox, tolerationBox] THEN RETURN[FALSE];
};
marginBox ¬ ExpandBox[enclosingBox, margin];
BiScrollersExtras.ShowBox[browser.biscroller, RectFromBox[marginBox], BiScrollersExtras.ViewerBox[browser.biscroller] ];
RETURN[TRUE];
};
CenterEverything: PUBLIC PROC [browser: BrowserHandle] ~ {
BiScrollersExtras.Fit[browser.biscroller]
};
SetMessageWindow: PUBLIC PROC [browser: BrowserHandle, contents: Rope.ROPE, times: INT ¬ 0, delayMSecs: INT ¬ 1000] ~ {
ViewerTools.SetContents[browser.messageWindow, Rope.Concat[" ", contents]];
UNTIL times <= 0 DO
Process.Pause[Process.MsecToTicks[delayMSecs]];
ViewerOps.BlinkViewer[browser.messageWindow];
times ¬ times - 1;
ENDLOOP;
};
*** Item Class Defaults ***
DefaultPaint: PUBLIC ItemPaintProc ~ {
box: BoundingBox ¬ self.class.boundingBox[self, commonData];
traj: Imager.Trajectory ¬ ImagerPath.MoveTo[ [box.lowerLeft.x, box.lowerLeft.y] ];
traj ¬ traj.LineTo[ [box.lowerLeft.x, box.upperRight.y] ];
traj ¬ traj.LineTo[ [box.upperRight.x, box.upperRight.y] ];
traj ¬ traj.LineTo[ [box.upperRight.x, box.lowerLeft.y] ];
traj ¬ traj.LineTo[ [box.lowerLeft.x, box.lowerLeft.y] ];
context.SetStrokeEnd[round];
SELECT how FROM
normal => {context.SetStrokeWidth[1.0]; context.SetColor[Imager.black]};
userSelected, clientSelected =>{context.SetStrokeWidth[2.0]; context.SetColor[Imager.black]};
deSelect => {context.SetStrokeWidth[2.0]; context.SetColor[Imager.white]};
ENDCASE;
context.MaskStrokeTrajectory[traj];
IF how = deSelect THEN {
context.SetStrokeWidth[1.0];
context.SetColor[Imager.black];
context.MaskStrokeTrajectory[traj]};
};
DefaultDistanceTo: PUBLIC ItemDistanceToProc ~ {
box: BoundingBox ¬ self.class.boundingBox[self, commonData];
xInside: BOOL ¬ (location.x >= box.lowerLeft.x) AND (location.x <= box.upperRight.x);
yInside: BOOL ¬ (location.y >= box.lowerLeft.y) AND (location.y <= box.upperRight.y);
xDistance, yDistance: REAL ¬ 0;
IF xInside AND yInside THEN RETURN[0.0];
xDistance ¬ IF location.x < box.lowerLeft.x THEN box.lowerLeft.x - location.x ELSE location.x - box.upperRight.x;
yDistance ¬ IF location.y < box.lowerLeft.y THEN box.lowerLeft.y - location.y ELSE location.y - box.upperRight.y;
IF xInside THEN RETURN[yDistance];
IF yInside THEN RETURN[xDistance];
RETURN[Vector.Mag[[xDistance, yDistance]]];
};
*** Bounding Box Routines ***
BoxFromRect: PROC [r: BiScrollers.Rect] RETURNS [b: BoundingBox] ~ {
b.lowerLeft.x ¬ r.x; b.lowerLeft.y ¬ r.y;
b.upperRight.x ¬ r.x + r.w; b.upperRight.y ¬ r.y + r.h;
};
RectFromBox: PROC [b: BoundingBox] RETURNS [r: BiScrollers.Rect] ~ {
r.x ¬ b.lowerLeft.x; r.y ¬ b.lowerLeft.y;
r.w ¬ b.upperRight.x - r.x; r.h ¬ b.upperRight.y - r.y;
};
LeastCommonBoundingBox: PUBLIC PROC [a, b: BoundingBox] RETURNS [c: BoundingBox] ~
{c.lowerLeft.x ¬ MIN[a.lowerLeft.x, b.lowerLeft.x];
c.lowerLeft.y ¬ MIN[a.lowerLeft.y, b.lowerLeft.y];
c.upperRight.x ¬ MAX[a.upperRight.x, b.upperRight.x];
c.upperRight.y ¬ MAX[a.upperRight.y, b.upperRight.y];
};
ExpandBox: PROC [b: BoundingBox, v: Vector.VEC] RETURNS [bb: BoundingBox] ~ {
bb.lowerLeft.x ¬ b.lowerLeft.x - v.x; bb.lowerLeft.y ¬ b.lowerLeft.y - v.y;
bb.upperRight.x ¬ b.upperRight.x + v.x; bb.upperRight.y ¬ b.upperRight.y + v.y;
};
Contains: PROC [a, b: BoundingBox] RETURNS [inside: BOOL] ~ {
RETURN[ (a.lowerLeft.x <= b.lowerLeft.x) AND (a.lowerLeft.y <= b.lowerLeft.y) AND
(a.upperRight.x >= b.upperRight.x) AND (a.upperRight.y >= b.upperRight.y)];
};
CurrentViewBox: PROC [bs: BiScrollers.BiScroller] RETURNS [v: BoundingBox] ~ {
v ¬ BoxFromRect[BiScrollers.ViewportBox[bs]];
};
Extrema: BiScrollers.ExtremaProc ~ {
my: Handle ¬ NARROW[clientData];
[min, max] ¬ Geom2D.ExtremaOfRect[RectFromBox[my.universe], direction];
};
END.