MoveChild:
PUBLIC
PROCEDURE[child: Viewer] =
TRUSTED BEGIN
parent: Viewer;
dx, dy: INTEGER;
grid: NAT;
creek: ClassIncreek.Increek ← ClassIncreek.NewStdIncreek[];
position: ClassIncreek.ViewPosition ← creek.GetPositionFrom[];
oldPosition: Interminal.MousePosition ← position.mousePosition;
actions: INTEGER ← 0;
saveMap: ImagerPixelMaps.PixelMap;
restoreMap: ImagerPixelMaps.PixelMap;
oldBox: ImagerManhattan.Polygon;
newBox: ImagerManhattan.Polygon;
parentBox: ImagerPixelMaps.DeviceRectangle;
toRestore, toSave: ImagerManhattan.Polygon;
screenX, screenY: INTEGER;
IF child # NIL THEN parent ← child.parent ELSE RETURN;
saveMap ← ImagerPixelMaps.Create[0, [0, 0, 808, 1024]];
restoreMap ← ImagerFrameBuffer.LFDisplay[];
[screenX, screenY] ← ViewerOps.UserToScreenCoords[parent.parent, parent.cx, parent.cy];
screenY ← restoreMap.sSize - screenY - parent.ch;
parentBox ← [screenY, screenX, parent.ch, parent.cw];
[screenX, screenY] ← ViewerOps.UserToScreenCoords[parent, child.wx, child.wy];
screenY ← restoreMap.sSize - screenY;
oldBox ← LIST[[screenY, screenX, child.wh, child.ww]];
ImagerPixelMaps.Fill[saveMap, oldBox.first, 0];
grid ← GetGrid[parent];
DO
a: ClassIncreek.ActionBody ← creek.GetAction[acceptance: clicksAndMotion];
WITH a
SELECT
FROM
keyUp => IF value = Red THEN EXIT;
ENDCASE;
only notice every moveGrain-th action
IF (actions MOD moveGrain) = 0 THEN {
dx ← position^.mousePosition.mouseX - oldPosition.mouseX;
dy ← -(position^.mousePosition.mouseY - oldPosition.mouseY);
IF dx = 0 AND dy = 0 THEN LOOP;
IF child.wx + dx < 0 THEN LOOP;
IF child.wy + dy < 0 THEN LOOP;
IF child.wx + child.ww + dx > parent.ww THEN EXIT;
IF child.wy + child.wh + dy > parent.wh THEN EXIT;
screenX ← screenX + dx;
screenY ← screenY + dy;
newBox ← LIST[[screenY, screenX, child.wh, child.ww]];
toRestore ← ImagerManhattan.Difference[oldBox, newBox];
toSave ← ImagerManhattan.Difference[newBox, oldBox];
save the to-be-obscured screen bits
FOR p:
LIST
OF ImagerPixelMaps.DeviceRectangle ← toSave, p.rest
UNTIL p=
NIL
DO
ImagerPixelMaps.Transfer[saveMap, ImagerPixelMaps.Clip[restoreMap, p.first]];
ENDLOOP;
move the entity
MoveViewer[child, child.wx + dx, child.wy + dy, child.ww, child.wh];
restore uncovered bits
FOR p:
LIST
OF ImagerPixelMaps.DeviceRectangle ← toRestore, p.rest
UNTIL p=
NIL
DO
ImagerPixelMaps.Transfer[ImagerPixelMaps.Clip[restoreMap, ImagerPixelMaps.Intersect[p.first, parentBox]], saveMap];
ENDLOOP;
oldPosition ← position^.mousePosition;
oldBox ← newBox };
actions ← actions + 1;
ENDLOOP;
child.parent.newVersion ← TRUE;
IF grid # 1
THEN
ViewerOps.MoveViewer[child, child.wx-(child.wx
MOD grid),
child.wy-(child.wy MOD grid), child.ww, child.wh, FALSE];
ViewerOps.PaintViewer[parent, all]; -- repaint everything
[] ← ClassIncreek.Release[creek];
WhiteboardDB.Move[child];
END;
GrowBox:
PUBLIC
PROCEDURE[wb: Viewer, box: Viewer, x, y:
INTEGER] =
TRUSTED BEGIN
dx, dy: INTEGER;
min, delta: INTEGER;
grid: NAT = GetGrid[wb];
corner: {ll, lr, ul, ur} ← ll;
creek: ClassIncreek.Increek ← ClassIncreek.NewStdIncreek[];
position: ClassIncreek.ViewPosition ← creek.GetPositionFrom[];
oldPosition: Interminal.MousePosition ← position.mousePosition;
actions: INTEGER ← 0;
saveMap: ImagerPixelMaps.PixelMap;
restoreMap: ImagerPixelMaps.PixelMap;
oldBox: ImagerManhattan.Polygon;
newBox: ImagerManhattan.Polygon;
wbBox: ImagerPixelMaps.DeviceRectangle;
toRestore, toSave: ImagerManhattan.Polygon;
screenX, screenY: INTEGER;
newX, newY, newW, newH: INTEGER;
IF box = NIL THEN RETURN;
saveMap ← ImagerPixelMaps.Create[0, [0, 0, 808, 1024]];
restoreMap ← ImagerFrameBuffer.LFDisplay[];
[screenX, screenY] ← ViewerOps.UserToScreenCoords[wb.parent, wb.cx, wb.cy];
screenY ← restoreMap.sSize - screenY - wb.ch;
wbBox ← [screenY, screenX, wb.ch, wb.cw];
[screenX, screenY] ← ViewerOps.UserToScreenCoords[wb, box.wx, box.wy];
screenY ← restoreMap.sSize - screenY;
oldBox ← LIST[[screenY, screenX, box.wh, box.ww]];
ImagerPixelMaps.Fill[saveMap, oldBox.first, 0];
choose the nearest corner
min ← delta ← LAST[INTEGER];
delta ← ABS[x - box.wx] + ABS[y - box.wy];
IF delta < min THEN {min ← delta; corner ← ul};
delta ← ABS[x - (box.wx + box.ww)] + ABS[y - box.wy];
IF delta < min THEN {min ← delta; corner ← ur};
delta ← ABS[x - box.wx] + ABS[y - (box.wy + box.wh)];
IF delta < min THEN {min ← delta; corner ← ll};
delta ← ABS[x - (box.wx + box.ww)] + ABS[y - (box.wy + box.wh)];
IF delta < min THEN {min ← delta; corner ← lr};
DO
a: ClassIncreek.ActionBody ← creek.GetAction[acceptance: clicksAndMotion];
WITH a
SELECT
FROM
keyUp => IF value = Blue THEN EXIT;
ENDCASE;
only notice every growGrain-th action
IF (actions MOD growGrain) = 0 THEN {
dx ← position^.mousePosition.mouseX - oldPosition.mouseX;
dy ← -(position^.mousePosition.mouseY - oldPosition.mouseY);
IF dx = 0 AND dy = 0 THEN LOOP;
set limits on where it can end up
IF (corner = ll OR corner = ul) AND box.wx + dx < 0 THEN LOOP;
IF (corner = ul OR corner = ur) AND box.wy + dy < 0 THEN LOOP;
IF (corner = ur OR corner = lr) AND box.wx + box.ww + dx > wb.ww THEN EXIT;
IF (corner = ll OR corner = lr) AND box.wy + box.wh + dy > wb.wh THEN EXIT;
set limits on the minimum size
IF (corner = lr OR corner = ur) AND box.ww + dx < boxW THEN LOOP;
IF (corner = ll OR corner = lr) AND box.wh + dy < boxH THEN LOOP;
IF (corner = ll OR corner = ul) AND box.ww - dx < boxW THEN LOOP;
IF (corner = ul OR corner = ur) AND box.wh - dy < boxH THEN LOOP;
move the corner
IF dx = 0 AND dy = 0 THEN LOOP;
SELECT corner FROM
ul => { newX ← box.wx + dx;
newY ← box.wy + dy;
newW ← box.ww - dx;
newH ← box.wh - dy;
screenX ← screenX + dx;
screenY ← screenY + dy };
ur => { newX ← box.wx;
newY ← box.wy + dy;
newW ← box.ww + dx;
newH ← box.wh - dy;
screenY ← screenY + dy };
ll => { newX ← box.wx + dx;
newY ← box.wy;
newW ← box.ww - dx;
newH ← box.wh + dy;
screenX ← screenX + dx };
lr => { newX ← box.wx;
newY ← box.wy;
newW ← box.ww + dx;
newH ← box.wh + dy };
ENDCASE;
newBox ← LIST[[screenY, screenX, newH, newW]];
toRestore ← ImagerManhattan.Difference[oldBox, newBox];
toSave ← ImagerManhattan.Difference[newBox, oldBox];
save the to-be-obscured screen bits
FOR p:
LIST
OF ImagerPixelMaps.DeviceRectangle ← toSave, p.rest
UNTIL p=
NIL
DO
ImagerPixelMaps.Transfer[saveMap, ImagerPixelMaps.Clip[restoreMap, p.first]];
ENDLOOP;
move the box
MoveViewer[box, newX, newY, newW, newH];
restore uncovered bits
FOR p:
LIST
OF ImagerPixelMaps.DeviceRectangle ← toRestore, p.rest
UNTIL p=
NIL
DO
ImagerPixelMaps.Transfer[ImagerPixelMaps.Clip[restoreMap, ImagerPixelMaps.Intersect[p.first, wbBox]], saveMap];
ENDLOOP;
oldPosition ← position^.mousePosition;
oldBox ← newBox };
actions ← actions + 1;
ENDLOOP;
wb.newVersion ← TRUE;
IF grid # 1
THEN
ViewerOps.MoveViewer[box, box.wx-(box.wx
MOD grid), box.wy-(box.wy
MOD grid),
box.ww-(box.ww MOD grid), box.wh-(box.wh MOD grid),
FALSE];
ViewerOps.PaintViewer[wb, all];
[] ← ClassIncreek.Release[creek];
WhiteboardDB.Grow[box];
END;
NearestChild:
PUBLIC
PROCEDURE[wb: Viewer, x, y:
INTEGER, type: ViewerFlavor ←
NIL]
RETURNS[nearest: Viewer] =
BEGIN
min, delta: INTEGER ← LAST[INTEGER];
IF wb.class.flavor = $WhiteboardIcon THEN {
IF type = NIL THEN RETURN[wb];
IF type = $WhiteboardIcon THEN RETURN[wb];
RETURN[NIL]};
FOR child: Viewer ← wb.child, child.sibling
DO
IF child = NIL THEN EXIT;
IF type # NIL AND child.class.flavor # type THEN LOOP;
IF x < child.wx
THEN delta ← child.wx - x
ELSE delta ← MAX[0, x - (child.wx + child.ww)];
IF y < child.wy
THEN delta ← delta + child.wy - y
ELSE delta ← delta + MAX[0, y - (child.wy + child.wh)];
IF delta > min
THEN
LOOP;
min ← delta;
nearest ← child;
ENDLOOP;
IF min > 40 THEN {nearest ← NIL; RETURN};
if you're looking for a text box, set the corner too
min ← delta ← LAST[INTEGER];
delta ← ABS[x - nearest.wx] + ABS[y - nearest.wy];
IF delta < min THEN {min ← delta; corner ← ul};
delta ← ABS[x - (nearest.wx + nearest.ww)] + ABS[y - nearest.wy];
IF delta < min THEN {min ← delta; corner ← ur};
delta ← ABS[x - nearest.wx] + ABS[y - (nearest.wy + nearest.wh)];
IF delta < min THEN {min ← delta; corner ← ll};
delta ← ABS[x - (nearest.wx + nearest.ww)] + ABS[y - (nearest.wy + nearest.wh)];
IF delta < min THEN {min ← delta; corner ← lr};
END;