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; }; 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]]]; }; 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. Τ 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 *** Item Class Defaults *** *** Bounding Box Routines *** Κ –(cedarcode) style•NewlineDelimiter ™šœ™Jšœ Οeœ1™Kšœ&˜&K˜uK˜Kšžœžœžœž œ˜)šžœžœž˜K˜ K˜`K˜!Kšžœ˜—K˜šžœžœžœ˜K˜3Kšžœ%žœžœžœ˜:K˜—K˜,Kšœx˜xKšžœžœ˜K˜—K˜šŸœžœžœ˜:Kšœ)˜)K˜—K˜š Ÿœžœžœ)žœ žœžœ ˜wK˜Lšžœ ž˜Kšœ/˜/Kšœ-˜-K˜Kšžœ˜—K˜—K˜Kšœ™K˜šŸ œžœ˜&K˜