[comp.sys.mac.programmer] Marquee Help?

sean@eleazar.dartmouth.edu (Sean P. Nolan) (01/05/90)

Hi ho...

I saw on here recently a passing mention that someone was using code that
produced the MacPaint-like Marquee around a selection. The Johnny Carson theme
comes to mind. But I have been trying, off-and-on, to figure out how to do
just that, given a selection rectangle and a nifty slot to do its thing in
my Event loop.

If anybody has the ah-ha insight on how to do this, I'd really appreciate a
note. Currently I shoved the problem aside and just InvertRect the selection,
which is uuuuuuuugly.

Thanks!

--- Sean

+----------------------------------------------------------------------------+
| Sean P. Nolan     | Net: Sean_Nolan@Mac.Dartmouth.EDU |  "Let's face it:   |
| Dartmouth College |                                   |   IBM is no fun."  |
| Hinman Box 2658   |            SCALP 'EM!             |     ::::::::::     |
| Hanover, NH 03755 |                                   |   John C. Dvorak   |
+----------------------------------------------------------------------------+

mtoy@sgi.com (Michael Toy) (01/06/90)

One way to get something marquee like, would be to use a set of
patterns of diagonal stripes the following example will draw
a cheap marquee rectangle, looping forever:

char p0[] = { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 };
char p1[] = { 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11, 0x88 };
char p2[] = { 0x22, 0x11, 0x88, 0x44, 0x22, 0x11, 0x88, 0x11 };
char p3[] = { 0x11, 0x88, 0x44, 0x22, 0x11, 0x88, 0x11, 0x22 };

marqueeRect(Rect *pRect)
{
	int patNum = 0;
	char *patterns[4];
	patterns[0] = p0; patterns[1] = p2; patterns[2] = p2; patterns[3] = p3;
	PenMode(patXor);	/* I'm not sure this is either the correct
				   function or parameter name */
	for (;;) {
		long t = TickCount();
		PenPat(patterns[patNum++]);
		patNum &= 3;
		FrameRect(pRect);		/* Draw a rectangle */
		while (TickCount() - t < 4)	/* Wait a bit */
			;
		FrameRect(pRect);		/* Undraw the rectangle */
	}
	PenNormal();
}

tim@hoptoad.uucp (Tim Maroney) (01/06/90)

In article <18304@dartvax.Dartmouth.EDU> sean@eleazar.dartmouth.edu
(Sean P. Nolan) writes:
>I saw on here recently a passing mention that someone was using code that
>produced the MacPaint-like Marquee around a selection. The Johnny Carson theme
>comes to mind. But I have been trying, off-and-on, to figure out how to do
>just that, given a selection rectangle and a nifty slot to do its thing in
>my Event loop.
>
>If anybody has the ah-ha insight on how to do this, I'd really appreciate a
>note. Currently I shoved the problem aside and just InvertRect the selection,
>which is uuuuuuuugly.

Might as well just post dwb's code that I got from a local BBS:

;
; (c) Copyright 1987, David W. Berry
;
				case		object
				string		pascal
				
				load	'MacStuff'
			
				export		MarqueeRect, MoveMarqueeRect

patterns		record		entry,decr
marqueePat		dc.l		$0f87c3e1, $f0783c1e
shiftPat		dc.l		$88442211, $88442211
				endr
			
;
;	Frame rectangle, using marquee pattern.  The rect is drawn in xor mode.
;	This procedure should be called to draw the marquee initially, then
;	MoveMarqueeRect should be called repeatedly to move the pattern.
;	Finally, call MarqueeRect again to erase the marquee.  The display
;	will end up the same as it was before.
;

MarqueeRect		proc		export

Frame			record		{a6link},decr
rect			ds.l		1
return			ds.l		1
a6link			ds.l		1
state			ds.b		psRec
locals			equ			*
				endr
			
				with		Frame
			
				link		a6,#locals
				pea			state(a6)
				_GetPenState
			
				_PenNormal
				
				pea			patterns.marqueePat
				_PenPat
			
				move.w		#patXor,-(a7)
				_PenMode
			
				move.l		rect(a6),-(a7)
				_FrameRect
			
				pea			state(a6)
				_SetPenState
				
				unlk		a6
				rts
			
				endproc
				
;
;	Frame rectangle, using pattern that moves the marquee.  Then shift
;	the pattern and the marquee pattern, to keep the two in sync.
;	This procedure must be called repeatedly to achieve the effect of
;	motion.
;

MoveMarqueeRect	proc	export

Frame			record	{a6link},decr
rect			ds.l	1
return			ds.l	1
a6link			ds.l	1
state			ds.b	psRec
locals			equ		*
				endr
				
				with	Frame
				
				link	a6,#locals
				
				pea		state(a6)
				_GetPenState
				
				_PenNormal
				
				pea		patterns.shiftPat
				_PenPat
				
				move	#patXor,-(a7)
				_PenMode
				
				move.l	rect(a6),-(a7)
				_FrameRect
				
				pea		state(a6)
				_SetPenState
				
	; shift the marquee pattern 1 slot to the left
				lea		patterns.marqueePat,a0
				bsr.s	rotate
	
	; likewise the shift pattern
				lea		patterns.shiftPat,a0
				bsr.s	rotate
				
				unlk	a6
				rts

rotate:			move.l		(a0),d1
				move.l		4(a0),d0
				rol.l		#8,d0
				rol.l		#8,d1
				move.b		d0,d2
				move.b		d1,d0
				move.b		d2,d1
				move.l		d1,(a0)
				move.l		d0,4(a0)
				rts

				endproc
				
				end
				

End of quoted code marquee.a.

Here's MPW C code I use for the same effect.  I'm afraid it's rather
environment-dependent, but you should still be able to break it to
your will.

static void RotatePatterns(Pattern marquee, Pattern shift)
{	unsigned char c;
	c = marquee[0];
	BlockMove(marquee + 1, marquee, 7);
	marquee[7] = c;
	c = shift[0];
	BlockMove(shift + 1, shift, 7);
	shift[7] = c;
}

static void
click(WindowPtr window, DocStorage **storage, EventRecord *event,
      Boolean *changed, Boolean *selected)
{	Point start, now; Rect r, r2; short tmp;
	DocInfo doc; Pattern marquee, shift; PenState pen;
#pragma unused (changed)
	unselect(window, storage);
	GetDocInfo(window, &doc);
	start = now = event->where;
	GetPenState(&pen);
	PenNormal();
	BlockMove((Ptr)(*storage)->marquee, (Ptr)marquee, 8);
	BlockMove((Ptr)(*storage)->shift, (Ptr)shift, 8);
	PenPat(marquee);
	PenMode(patXor);
	SetRect(&r, start.h, start.v, now.h, now.v);
	FrameRect(&r);
	while (WaitMouseUp()) {
		PenPat(shift);
		FrameRect(&r);
		RotatePatterns(marquee, shift);
		GetMouse(&now);
		SetRect(&r2, start.h, start.v, now.h, now.v);
		if (r2.left > r2.right)
			{ tmp = r2.left; r2.left = r2.right; r2.right = tmp; }
		if (r2.top > r2.bottom)
			{ tmp = r2.top; r2.top = r2.bottom; r2.bottom = tmp; }
		if (EqualRect(&r, &r2)) continue;
		PenPat(marquee);
		FrameRect(&r);
		FrameRect(&r2);
		r = r2;
	}
	if (*selected = !EmptyRect(&r))
		OffsetRect(&r, GetCtlValue(doc.hScroll), GetCtlValue(doc.vScroll));
	else {	PenPat(marquee); FrameRect(&r); SetRect(&r, 0, 0, 0, 0); }
	BlockMove((Ptr)marquee, (Ptr)(*storage)->marquee, 8);
	BlockMove((Ptr)shift, (Ptr)(*storage)->shift, 8);
	(*storage)->selRect = r;
	SetPenState(&pen);
}

static void idle(WindowPtr window, DocStorage **storage)
{	Pattern marquee, shift; Rect r; PenState pen; DocInfo doc;
	r = (*storage)->selRect;
	if (EmptyRect(&r)) return;
	GetDocInfo(window, &doc);
	GetPenState(&pen);
	PenNormal();
	BlockMove((Ptr)(*storage)->marquee, (Ptr)marquee, 8);
	BlockMove((Ptr)(*storage)->shift, (Ptr)shift, 8);
	PenPat(shift);
	PenMode(patXor);
	OffsetRect(&r, -GetCtlValue(doc.hScroll), -GetCtlValue(doc.vScroll));
	FrameRect(&r);
	RotatePatterns(marquee, shift);
	BlockMove((Ptr)marquee, (Ptr)(*storage)->marquee, 8);
	BlockMove((Ptr)shift, (Ptr)(*storage)->shift, 8);
	SetPenState(&pen);
}

And in Rez, the patterns are:

resource 'PAT#' (33) { {
	$"0f 87 c3 e1 f0 78 3c 1e" ,
	$"88 44 22 11 88 44 22 11"
} };
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com

"Gorbachev is returning to the heritage of the great Lenin" - Ronald Reagan

lsr@Apple.COM (Larry Rosenstein) (01/09/90)

>	PenMode(patXor);	/* I'm not sure this is either the correct

If you are doing this in a bitmap, then you should use patCopy.  patXOR
might look better in a structured graphics program, where there is always a
lot of white space.  (If you use patCopy then to erase the marquee you have
to redraw the contents of the rectangle.0

>		PenPat(patterns[patNum++]);
>		patNum &= 3;
>		FrameRect(pRect);		/* Draw a rectangle */
>		while (TickCount() - t < 4)	/* Wait a bit */

Another way to do this is to choose the pattern based on the value of
TickCount % 4 (or TickCount % 8 if you use 8 patterns).  The advantage is
that the ants will move at the same speed regardless of the size of the
rectangle.  The disadvantage is that you may get jerky motion if your loop
can't keep up.

-- 
		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 46-B  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr

dwb@archer.apple.com (David W. Berry) (01/09/90)

In article <9518@hoptoad.uucp> tim@hoptoad.UUCP (Tim Maroney) writes:
>;
>; (c) Copyright 1987, David W. Berry
>;
	I might point out that where I a real jerk, this is a violation
of the copyright above.  However, permission is granted for any non-commercial
usage of the code.  Those of you that wish to use it in a commercial
product can either contact me, or transliterate yourself...  It's not
that difficult once you understand the concepts.  BTW, this is derived
from a C version posted sometime ago by somebody else, I turned it into
assembler to speed it up (significantly as it turns out)