[comp.sys.mac.programmer] GrowWindow Woes, Help Please

englhq@jetson.uh.edu (04/20/91)

I'm working through the window techniques in Huxham, Burnard and Takatsuka's
USING THE MACINTOSH TOOLBOX WITH C, and I'm stuck at the GrowWindow function.
The code goes like this:

case inGrow:
     newSize=GrowWindow(whichWindow,theEvent.where,&limitRect);
     SizeWindow(whichWindow, LoWord(newSize),HiWord(newSize),0xff);
     contRgnHnd=theWindowRec.contRgn;
     tempRect=(*contRgnHnd)->rgnBBox;
     EraseRect(&tempRect);
     DrawGrowIcon(theWindow);
     break; 

What happens is, the outline of the scroll bars and size box remain in the
middle of the window. i.e. It seems that the EraseRect isn't doing what I
think it's supposed to.

The maddening part of this is that when I step through with the debugger
everything performs as advertised; tempRect has the correct coordinates
and the content region is erased just fine.

WHAT IS GOING ON HERE?? As soon as I remove the breakpoint, the window goes
back to its old tricks. Any advice is greatly appreciated. 

Duane Franklet
englhq@jetson.uh.edu

Henry_Van_Tunen@mindlink.bc.ca (Henry Van Tunen) (04/22/91)

The content region of the window is in global coordinates. It
is simpler to use the window's portRect.
In Pascal use: EraseRect (whichWindow^.portRect);

Hank van Tunen

dedreb@arco.com (Richard Beecher) (04/22/91)

In article <9190.2810258e@jetson.uh.edu> englhq@jetson.uh.edu writes:
>I'm working through the window techniques in Huxham, Burnard and Takatsuka's
>USING THE MACINTOSH TOOLBOX WITH C, and I'm stuck at the GrowWindow function.
>The code goes like this:
>
>case inGrow:
>     newSize=GrowWindow(whichWindow,theEvent.where,&limitRect);
>     SizeWindow(whichWindow, LoWord(newSize),HiWord(newSize),0xff);
>     contRgnHnd=theWindowRec.contRgn;
>     tempRect=(*contRgnHnd)->rgnBBox;
>     EraseRect(&tempRect);
>     DrawGrowIcon(theWindow);
>     break; 
>
>What happens is, the outline of the scroll bars and size box remain in the
>middle of the window. i.e. It seems that the EraseRect isn't doing what I
>think it's supposed to.
>

Can't say that I know exactly what is happening here, but I wonder if a simpler
approach would fix the problem.  In the above code, you are referencing
whichWindow, theWindowRec, and theWindow.  How about trying the following code?

case inGrow:
     newSize=GrowWindow(whichWindow,theEvent.where,&limitRect);
     EraseRect(&whichWindow->portRect);
     SizeWindow(whichWindow, LoWord(newSize),HiWord(newSize),0xff);
     DrawGrowIcon(whichWindow);
     break;

Here, I only reference whichWindow.  Also, for aesthetic reasons, I EraseRect
before resizing the window.  I think Apple also recommends this in the user
interface guidelines (IM-1 section on Window Manager?).

Erasing the window's portRect should accomplish the same thing as erasing its
content region.  Ah hah!  I might be on to something hereQthe window's content
region is expressed in global coordinates...its portRect is expressed in local
coordinates.  This might be the source of your problem.  Essentially, you are
erasing a rectangle that is outside your window's clipRgn.  So if you want to
stick with your original code, converting tempRect to local coordinates might
fix your problem.

Good luck!

---------------
Richard Beecher
dedreb@arco.com
---------------

wdh@well.sf.ca.us (Bill Hofmann) (04/24/91)

In article <9190.2810258e@jetson.uh.edu> englhq@jetson.uh.edu writes:
>case inGrow:
>     newSize=GrowWindow(whichWindow,theEvent.where,&limitRect);
>     SizeWindow(whichWindow, LoWord(newSize),HiWord(newSize),0xff);
>     contRgnHnd=theWindowRec.contRgn;
>     tempRect=(*contRgnHnd)->rgnBBox;
>     EraseRect(&tempRect);
>     DrawGrowIcon(theWindow);
>     break; 
>
>What happens is, the outline of the scroll bars and size box remain in the
>middle of the window. i.e. It seems that the EraseRect isn't doing what I
>think it's supposed to.

Yes.  Rather, you aren't quite clear on what the responsibilities of your
application are.  There are several problems with this code.

1. GrowWindow returns 0 if the user doesn't actually move the mouse before
releasing the mouse button.  So your code will do funny things in this case.
Only call the rest of the code if GrowWindow returns non-zero

2. SizeWindow's last argument is a Boolean, it's safer to use TRUE or FALSE.
This isn't what's causing a problem.

3. **YOU** are responsible for moving scrollbars.  I don't see code to do this.

4. If SizeWindow's last argument is TRUE, the area that is **newly exposed**
by the resize is accumulated into the window's update region.  Your problem
comes because the scrollbars and the grow icon aren't **newly exposed** when
the window is made bigger.  When the window is made smaller, **nothing** is
newly exposed.  The entire Toolbox makes NO assumptions about what you put
in your content.  If you want portions of your content redrawn, you must
invalidate them yourself.

5. BTW, there shouldn't ever really be a reason to use the contentRgn, you
can use the portRect.  As the previous respondent points out, contentRgn is
in global coordinates, and all drawing is done in local coordinates, which
are the coordinates portRect is in.

6. Here's a sample inGrow:

case inGrow:
{	/* I've put variables here just for clarity */
	/* I'm assuming wp is the window's WindowPtr, event.where
	 *  is the event record's mouse loc, in global coords */
	long	result;
	Rect	bounds;
	Rect	inval;

	SetRect(&bounds, 50,50, 500,500);
	if (result = GrowWindow(wp, event.where, &bounds))
	{
	/* First, invalidate the area that the grow icon takes before */
	SetPort(wp);
	inval = wp->portRect;
	inval.left = inval.right-15;
	inval.top = inval.bottom-15;
	InvalRect(&inval);

	/* Then, size the window */
	SizeWindow(wp, LoWord(result), HiWord(result), true);

	/* Then, invalidate where the grow icon now is, and move scrollbars */
	inval = wp->portRect;
	inval.left = inval.right-15;
	inval.top = inval.bottom-15;
	InvalRect(&inval);

	/* I'm assuming the vscroll and hscroll are the 2 scroll bars. */
	/* You figure out how to get them.  You might put them in a
	 *  data structure you store in the window's refCon with 
	 *  SetWRefCon
	 */
	HideControl(vscroll);
	MoveControl(vscroll, wp->portRect.right-15, wp->portRect.top-1);
	SizeControl(vscroll, 16, (wp->portRect.bottom-14) -
				 (wp->portRect.top - 1));
	ShowControl(vscroll);
	inval = (*vscroll)->contrlRect;
	ValidRect(&inval);	/* ShowControl draws, don't need to redraw */

	HideControl(hscroll);
	MoveControl(hscroll, wp->portRect.left-1, wp->portRect.bottom-15);
	SizeControl(hscroll, (wp->portRect.right-14) -
				 (wp->portRect.left - 1), 16);
	ShowControl(hscroll);
	inval = (*hscroll)->contrlRect;
	ValidRect(&inval);	/* ShowControl draws, don't need to redraw */
	}
	break;

If you don't have scrollbars, you'll need to invalidate the entire area where
they'd be, both before and after the SizeWindow.  HideControl invals where
the control is after it erases the rect, so it's taken care of in this case.
This code is the minimum to avoid unnecessary redraws.

You don't need to EraseRect, because your update routine should do that 
immediately after the BeginUpdate call.  Similarly, DrawGrowIcon belongs
only 2 places: in activate and update.  In activate, it shows the changed
state of the window, and in update, it redraws what needs to be drawn.

Hope this helps.
-Bill Hofmann