<> <> <> DIRECTORY Convert USING [ValueToRope], Cursors USING [AddCursorCorner, SetCursor], Graphics USING [Context, DrawBox, SetPaintMode, SetStipple], InputFocus USING [CaptureButtons, ReleaseButtons], MessageWindow USING [Append, Clear], Process USING [Detach], Rope USING [Cat, ROPE], TIPUser USING [InstantiateNewTIPTable, TIPScreenCoords, TIPTable], ViewerAdjust, ViewerClasses USING [NotifyProc, Viewer], ViewerMenus, ViewerOps, ViewerSpecs, WindowManager USING [RestoreCursor]; ViewerAdjustImpl: CEDAR MONITOR IMPORTS Convert, Cursors, Graphics, InputFocus, MessageWindow, Process, Rope, TIPUser, ViewerOps, ViewerSpecs, WindowManager EXPORTS ViewerAdjust SHARES ViewerClasses, ViewerOps = BEGIN OPEN ViewerClasses; viewerMinHeight: INTEGER ~ ViewerSpecs.captionHeight; Adjust: PUBLIC ENTRY PROC [viewer: Viewer, sticky: BOOL _ TRUE] = BEGIN grey: CARDINAL ~ 122645B; InputFocus.CaptureButtons[BoundaryAdjustNotify, vaTIP, viewer]; context _ ViewerOps.AcquireContext[NIL]; [] _ Graphics.SetPaintMode[context, invert]; Graphics.SetStipple[context, grey]; [minY, maxY] _ ComputeYBounds[viewer]; xPos _ viewer.wx; width _ viewer.ww; stickyHeight _ sticky; adjustBottom _ FALSE; END; AdjustMode: TYPE = {top, bottom, column, none} ; stickyHeight, adjustBottom: BOOL; mode: AdjustMode _ none; lastX, lastY: INTEGER _ LAST[INTEGER]; context: Graphics.Context; maxY, minY, xPos, width: INTEGER; 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; BoundaryAdjustNotify: NotifyProc = BEGIN ENABLE UNWIND => {InputFocus.ReleaseButtons[]; ViewerOps.ReleaseContext[context]}; 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 => BEGIN ChangeMode[none, 0, 0]; InputFocus.ReleaseButtons[]; ViewerOps.ReleaseContext[context]; 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; END; $Move => BEGIN 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 => BEGIN ViewerOps.PaintViewer[self, caption]; ChangeMode[top, mouseX, mouseY]; END; END; $End => BEGIN change: AdjustMode _ mode; ChangeMode[none, 0, 0]; InputFocus.ReleaseButtons[]; ViewerOps.ReleaseContext[context]; SELECT change FROM top => BEGIN self.position _ MAX[viewerMinHeight, mouseY-self.wy]; IF stickyHeight THEN self.openHeight _ self.position; ViewerOps.ComputeColumn[self.column]; END; bottom => BEGIN self.position _ MAX[viewerMinHeight, self.wy+self.wh-mouseY]; IF stickyHeight THEN self.openHeight _ self.position; ViewerOps.ComputeColumn[self.column]; END; column => ViewerOps.MoveBoundary[mouseX, mouseY]; ENDCASE; END; ENDCASE => NULL; z: TIPUser.TIPScreenCoords => [mouseX, mouseY] _ Clip[z]; ENDCASE => ERROR; ENDLOOP; END; ChangeMode: PROC [newMode: AdjustMode, mouseX, mouseY: INTEGER] = BEGIN 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]; SetMsg[]}; ENDCASE => {WindowManager.RestoreCursor[]; SetMsg[]}; mode _ newMode; IF mode#none THEN Feedback[mouseX, mouseY]; END; SetMsg: PROC [msg: Rope.ROPE _ NIL] = TRUSTED INLINE BEGIN <> IF msg=NIL THEN Process.Detach[FORK MessageWindow.Clear[]] ELSE Process.Detach[FORK MessageWindow.Append[msg, TRUE]]; END; Feedback: PROC [x, y: INTEGER, remove: BOOL _ FALSE] = BEGIN Show: PROC [x, y: INTEGER] = BEGIN IF mode=column THEN BEGIN Graphics.DrawBox[context, [x-1, y, x+1, ViewerSpecs.openLeftTopY]]; Graphics.DrawBox[context, [0, y-1, ViewerSpecs.screenW, y+1]]; END ELSE Graphics.DrawBox[context, [xPos, y+1, xPos+width, y-1]]; END; IF lastX=x AND lastY=y THEN RETURN; -- no change IF lastX#LAST[INTEGER] THEN Show[lastX, lastY]; IF remove THEN lastX _ lastY _ LAST[INTEGER] ELSE {Show[x, y]; lastX _ x; lastY _ y}; END; Clip: PROC [position: TIPUser.TIPScreenCoords] RETURNS [x, y: INTEGER] = BEGIN OPEN ViewerSpecs; x _ position.mouseX; IF mode=column THEN BEGIN IF position.mouseY <= openBottomY THEN adjustBottom _ TRUE; IF adjustBottom THEN y _ SELECT position.mouseY FROM < iconHeight => position.mouseY, < iconHeight+iconSpacing+(iconHeight/2) => iconHeight+iconSpacing, ENDCASE => 2*(iconHeight+iconSpacing) ELSE y _ openBottomY; END ELSE y _ SELECT position.mouseY FROM < minY => minY, > maxY => maxY, ENDCASE => position.mouseY END; vaTIP: TIPUser.TIPTable _ TIPUser.InstantiateNewTIPTable["/Indigo/CedarViewers/Viewers/ViewerAdjust.tip"]; END.