ViewerAdjustImpl.mesa
Copyright © 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
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, maxY] ← ComputeYBounds[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 => {
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;
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.position ← MAX[viewerMinHeight, mouseY-self.wy];
IF stickyHeight THEN self.openHeight ← self.position;
self.openHeight ← MAX[viewerMinHeight, mouseY-self.wy];
ViewerOps.ComputeColumn[self.column];
};
bottom => {
self.position ← MAX[viewerMinHeight, self.wy+self.wh-mouseY];
IF stickyHeight THEN self.openHeight ← self.position;
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;
Addition by Randy Pausch: "snap" to the default setting for the two columns, and to the center
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 above first row, then snap to nearest row boundary
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.
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;