[comp.sys.mac] Cummulative Scrolling

liberte@uiucdcsb.cs.uiuc.edu (12/05/86)

It took several hours for me to figure out how to do the following scrolling
trick, so I thought I would maybe save some other people time by posting
how I did it, and maybe learn an easier way to do it.

What I wanted to do was allow multiple scrolling requests to be accumulated
before the window updating actually takes place.  This is a desirable behaviour
in the case that the update would take along time.  The problem is that each
scrolling action would normally scroll the whole window some small amount,
but this results in the updateRgn returned by scrollRect always overlapping
the previous updateRgns, or nearly so.  Changing the window origin for
each scrolling action does not help matters since the updateRgn is in
global coordinates.

The solution is to only scroll the good data that remains in the window
by subtracting out the previous updateRgn.  A further complication is that
part of the window may not be on the screen, so one must intersect with the
current visible region as well.

Another thing I learned along the way was to never switch ports in the middle
of an update.  It would be handy to be able to write debugging stuff out to
Lightspeed Pascals Text window while doing an update, but something isn't
properly recovered afterwards.

Below is the scrolling code.


Dan LaLiberte
liberte@b.cs.uiuc.edu
liberte@uiuc.csnet
ihnp4!uiucdcs!liberte


PROCEDURE ContourScroll (dh, dv : integer);
{ Determine the minimum amount of scrolling required to update the window. }
{ Only scroll the plotRect, without the previous update region, }
{ and inside the visible region.  ScrollRect then returns the correct
	update region. }
VAR
	updateRgn : RgnHandle;
	plotRgn : RgnHandle;
	copyUpdate : RgnHandle;
	peek : WindowPeek;
	ScrollR : Rect;
BEGIN
	SetPort(ContourWindow);
	peek := WindowPeek(ContourWindow);
	fixPlotRect;		{ set up the plotRect once again }

	{ first optain a copy of the current update region }
	copyUpdate := NewRgn;
	CopyRgn(peek^.updateRgn, copyUpdate);

	{ give the region local coordinates  - note that the updateRgn is in
		global coordinates }
	WITH ContourWindow^.portBits.bounds DO
		OffsetRgn(copyUpdate, left, top);

	{ make a region out of the whole plotting rectangle }
	plotRgn := NewRgn;
	RectRgn(plotRgn, plotRect);

	{ remove the current update region }
	DiffRgn(plotRgn, copyUpdate, plotRgn);
	{ intersect with the current visible region }
	SectRgn(plotRgn, ContourWindow^.VisRgn, plotRgn);

	{ Get the scrolling rectangle from the resulting region's
		bounding box }
	scrollR := plotRgn^^.rgnBBox;

	DisposeRgn(copyUpdate);
	DisposeRgn(plotRgn);

	{ Scroll the rectangle and invalidate the returned updateRgn }
	updateRgn := NewRgn;
	ScrollRect(scrollR, dh, dv, updateRgn);
	InvalRgn(updateRgn);

	DisposeRgn(updateRgn);

END;