DIRECTORY Cursors USING [AddCursorCorner, SetCursor], Imager USING [Color, Context, MaskRectangleI, SetColor], ImagerBackdoor USING [MakeStipple], InputFocus USING [CaptureButtons, ReleaseButtons], Rope USING [ROPE], TIPUser USING [InstantiateNewTIPTable, TIPScreenCoords, TIPTable], ViewerClasses USING [NotifyProc, Viewer], ViewerOps USING [ComputeColumn, MoveBoundary, PaintViewer], ViewerPrivate USING [LockViewerTree, PaintScreen, ReleaseViewerTree], ViewerSpecs USING [bwScreenWidth, captionHeight, iconHeight, iconRows, iconSpacing, openBottomY, openTopY], WindowManager USING [RestoreCursor]; ViewerAdjustImpl: CEDAR MONITOR IMPORTS Cursors, Imager, ImagerBackdoor, InputFocus, TIPUser, ViewerOps, ViewerPrivate, ViewerSpecs, WindowManager EXPORTS ViewerOps = BEGIN OPEN ViewerClasses; AdjustMode: TYPE = {top, bottom, column, none}; mode: AdjustMode _ none; stickyHeight, adjustBottom: BOOL; xPos, width, minY, maxY: INTEGER; lastX, lastY: INTEGER _ LAST[INTEGER]; Adjust: PUBLIC ENTRY PROC [viewer: Viewer, sticky: BOOL _ TRUE] = { ViewerPrivate.LockViewerTree[]; InputFocus.CaptureButtons[BoundaryAdjustNotify, vaTIP, viewer]; minY _ ViewerSpecs.openBottomY; maxY _ ViewerSpecs.openTopY; xPos _ viewer.wx; width _ viewer.ww; stickyHeight _ sticky; adjustBottom _ FALSE; }; EndAdjust: PROC = { ChangeMode[none, 0, 0]; InputFocus.ReleaseButtons[]; ViewerPrivate.ReleaseViewerTree[]; }; BoundaryAdjustNotify: NotifyProc = { ENABLE UNWIND => EndAdjust[]; mouseX, mouseY: INTEGER; FOR list: LIST OF REF ANY _ input, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM x: ATOM => SELECT x FROM $Abort => { EndAdjust[]; IF self.openHeight = 0 THEN ViewerOps.PaintViewer[self, caption] ELSE {self.openHeight _ 0; ViewerOps.ComputeColumn[self.column]}; }; $Move => { SELECT mode FROM top => IF mouseX NOT IN [self.wx..self.wx+self.ww) THEN ChangeMode[column, mouseX, mouseY] ELSE IF mouseY <= self.wy THEN ChangeMode[bottom, mouseX, mouseY] ELSE Feedback[mouseX, mouseY]; bottom => IF mouseX NOT IN [self.wx..self.wx+self.ww) THEN ChangeMode[column, mouseX, mouseY] ELSE IF mouseY >= self.wy+self.wh THEN ChangeMode[top, mouseX, mouseY] ELSE Feedback[mouseX, mouseY]; column => Feedback[mouseX, mouseY]; ENDCASE => { ViewerOps.PaintViewer[self, caption]; ChangeMode[top, mouseX, mouseY]; }; }; $End => { viewerMinHeight: NAT ~ ViewerSpecs.captionHeight; change: AdjustMode _ mode; EndAdjust[]; SELECT change FROM top => { self.openHeight _ MAX[viewerMinHeight, mouseY-self.wy]; ViewerOps.ComputeColumn[self.column]; }; bottom => { self.openHeight _ MAX[viewerMinHeight, self.wy+self.wh-mouseY]; ViewerOps.ComputeColumn[self.column]; }; column => ViewerOps.MoveBoundary[mouseX, mouseY]; ENDCASE; }; ENDCASE => NULL; z: TIPUser.TIPScreenCoords => [mouseX, mouseY] _ Clip[z]; ENDCASE => ERROR; ENDLOOP; }; ChangeMode: PROC [newMode: AdjustMode, mouseX, mouseY: INTEGER] = { Feedback[LAST[INTEGER], LAST[INTEGER], TRUE]; SELECT newMode FROM top => {Cursors.SetCursor[pointUp]; Cursors.AddCursorCorner[upperSide]}; bottom => {Cursors.SetCursor[pointDown]; Cursors.AddCursorCorner[lowerSide]}; column => {Cursors.SetCursor[activate]}; ENDCASE => {WindowManager.RestoreCursor[]}; mode _ newMode; IF mode#none THEN Feedback[mouseX, mouseY]; }; adjustStipple: Imager.Color ~ ImagerBackdoor.MakeStipple[stipple: 122645B, xor: TRUE]; Feedback: PROC [x, y: INTEGER, remove: BOOL _ FALSE] = { action: PROC [context: Imager.Context] ~ { Show: PROC [x, y: INTEGER] = { IF mode=column THEN { Imager.MaskRectangleI[context, x-1, y, 2, ViewerSpecs.openTopY-y]; Imager.MaskRectangleI[context, 0, y-1, ViewerSpecs.bwScreenWidth, 2]; } ELSE Imager.MaskRectangleI[context, xPos, y-1, width, 2]; }; IF lastX=x AND lastY=y THEN RETURN; -- no change Imager.SetColor[context, adjustStipple]; IF lastX#LAST[INTEGER] THEN Show[lastX, lastY]; IF remove THEN lastX _ lastY _ LAST[INTEGER] ELSE {Show[x, y]; lastX _ x; lastY _ y}; }; ViewerPrivate.PaintScreen[bw, action, FALSE]; }; standardLeftWidth: INTEGER ~ 600; -- should be in ViewerSpecs Clip: PROC [position: TIPUser.TIPScreenCoords] RETURNS [x, y: INTEGER] = { OPEN ViewerSpecs; fudge: INTEGER = 15; screenW: INTEGER ~ ViewerSpecs.bwScreenWidth; x _ position.mouseX; y _ position.mouseY; IF ABS[x-(screenW/2)] < fudge THEN x _ (screenW/2) ELSE IF ABS[x-standardLeftWidth] < fudge THEN x _ standardLeftWidth; IF mode=column THEN { IF y<=openBottomY THEN adjustBottom _ TRUE; -- must move below column to adjust bottom IF adjustBottom THEN { rowHeight: INTEGER = iconHeight+iconSpacing; IF y>rowHeight THEN { rows: INTEGER = MIN[(y+iconHeight/2), maxY]/rowHeight; y _ MIN[rows, iconRows]*rowHeight; }; } ELSE y _ openBottomY; -- pin y if not adjusting bottom } ELSE y _ MIN[maxY, MAX[minY, y]]; }; vaTIP: TIPUser.TIPTable _ TIPUser.InstantiateNewTIPTable["ViewerAdjust.tip"]; END. ViewerAdjustImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. McGregor on January 6, 1983 2:21 pm Maxwell, May 20, 1983 9:58 am Russ Atkinson, November 18, 1983 1:31 pm Doug Wyatt, April 15, 1985 5:51:09 pm PST [minY, maxY] _ ComputeYBounds[viewer]; IF self.position=0 THEN ViewerOps.PaintViewer[self, caption] ELSE BEGIN self.position _ 0; IF stickyHeight THEN self.openHeight _ self.position; ViewerOps.ComputeColumn[self.column]; END; self.position _ MAX[viewerMinHeight, mouseY-self.wy]; IF stickyHeight THEN self.openHeight _ self.position; self.position _ MAX[viewerMinHeight, self.wy+self.wh-mouseY]; IF stickyHeight THEN self.openHeight _ self.position; Addition by Randy Pausch: "snap" to the default setting for the two columns, and to the center If above first row, then snap to nearest row boundary ComputeYBounds: PROC [viewer: Viewer] RETURNS [min, max: INTEGER] = BEGIN OPEN ViewerSpecs; LimitProc: ViewerOps.EnumProc = BEGIN IF v.column=viewer.column AND NOT v.iconic THEN columnRequested _ columnRequested + MAX[viewerMinHeight, (IF v.position#0 THEN v.position ELSE v.openHeight)]; END; columnRequested: INTEGER _ 0; columnFree, percent: INTEGER; columnSpace: INTEGER ~ openLeftTopY-openBottomY; ViewerOps.EnumerateViewers[LimitProc]; percent _ 10*((11*columnRequested-1)/columnSpace); -- round up SetMsg[Rope.Cat["The ", SELECT viewer.column FROM left => "left", right => "right", ENDCASE => "color", " column is constrained ", Convert.ValueToRope[[signed[percent, 10]]], "%"]]; columnFree _ MAX[0, columnSpace - columnRequested - (viewer.wh-(IF viewer.position#0 THEN viewer.position ELSE viewer.openHeight))]; min _ MAX[MIN[viewer.wy, viewer.wy-columnFree], openBottomY]; max _ MIN[MAX[viewer.wy+viewer.wh, viewer.wy+viewer.wh+columnFree], openLeftTopY]; END; ΚS˜codešœ™Kšœ Οmœ1™™Kšžœžœ#žœ ™OK™M—šœ žœ#™3Kšœ žœžœžœ™P—Kšœžœžœ0™=KšœžœžœE™RKšžœ™K™——K˜K˜—…—ζ!M