[comp.sys.mac] Scroll bars in Modal Dialogs

mdm0@bunny.UUCP (Michael Maggio) (11/13/86)

I have been having trouble trying to get a simple
scroll bar to function in a modal dialog.  I use
Resedit to define the dialog and the scroll bar,
then in my code (LightspeedC) I define my control
routine to increment/decrement by a certain number
depending on the partcode (uparrow, downarrow, etc.)
When I run the program, the thumb bar can be moved,
but if I press another part of the control, then try
to move the thumb, I get into trouble...

Im sorry this description is sketchy, but I would appreciate
ANY suggestions on whats wrong or how to do a scroll
bar in general.  By the way, why doesn't the "default"
routine for a scroll bar handle the arrows?

Thanks for any suggestions....

-- 
Michael David Maggio 

thomas@utah-gr.UUCP (Spencer W. Thomas) (11/14/86)

[Note: I am cross posting because this message came in here on
net.micro.mac, so I want to make sure the original poster sees the
response.]

I think you are hitting a well-known bug in the handling of scroll bar
controls.  It is even documented in IM (if you know what you are looking
for).  The actionProc will be called with two arguments (the control
handle and the part code), *except* when moving the thumb.  In assembly
language, you can do a hack to try and determine which it is (since you
want to just return for thumb actions, anyway), by looking at the
supposed "theControl" argument and seeing if it is the handle to your
control.  This is not certain, since the garbage on the stack could
possibly have the same value you are looking for. 

In LSC, there seems to be nothing you can do about this. The problem is
that the actionProc is a "pascal" procedure, so it will unstack the
arguments on return.  If it was called with NO arguments, this can be a
disaster.

The problem comes up worst when using controls inside a dialog, since
you don't have the option of whether you pass an actionProc based on
which part of the control is hit.  If the control is in an ordinary
window, you can pass a NIL actionProc when the thumb is selected.

Hope this explanation makes sense, it feels a lit disjointed to me.

As an example, here is an actionProc I wrote using Sumacc.

/* 
 * XL_ScrollAdj - Scroll an adjuster control.
 * Since this is called from inside a dialogue, we have no control
 * over what part of the scroll bar the user may have chosen.  If the
 * thumb was picked, this routine will be called with no arguments.
 * Use a kludge to detect this.  If args were passed, pick them with
 * getpargs into the struct below.
 */
struct TCargs {         /* args passed from Pascal TrackControl */
        short   theCode;
        ControlHandle whichControl;
};

XL_ScrollAdj(args)
struct TCargs args;
{
	register int i;
        struct TCargs a;

	/* Oh what a kludge.  If called because user is moving thumb
	 * directly, no args are passed.  Hopefully, this will detect
	 * that.  We don't want to unstack the args if there aren't any!
	 * 
	 * Note also dependency on a single global adjuster window.
	 */
	for ( i = 0; i < 7; i++ )
	    if ( args.whichControl == XL_Adjust_wind.u.adj.adjCtl[i] )
		break;
	if ( i >= 7 )
	    return;			/* nope, no match, so no args */

	/* Getpargs pops the args off the stack */
        getpargs(&a, sizeof a);

	switch( a.theCode )
	{
	    case inUpButton:
		SetCtlValue(a.whichControl,GetCtlValue(a.whichControl)-1);
		break;
	    case inDownButton:
		SetCtlValue(a.whichControl,GetCtlValue(a.whichControl)+1);
		break;
	    case inPageUp:
		SetCtlValue(a.whichControl,GetCtlValue(a.whichControl)-10);
		break;
	    case inPageDown:
		SetCtlValue(a.whichControl,GetCtlValue(a.whichControl)+10);
		break;
	}
	XL_adjustItem = i + 1;		/* end-run around DialogSelect */
}

-- 
=Spencer   ({ihnp4,decvax}!utah-cs!thomas, thomas@utah-cs.ARPA)

lsr@apple.UUCP (11/22/86)

In article <1845@utah-gr.UUCP> thomas@utah-gr.UUCP (Spencer W. Thomas) writes:
>
>I think you are hitting a well-known bug in the handling of scroll bar
>controls.  It is even documented in IM (if you know what you are looking
>for).  The actionProc will be called with two arguments (the control
>handle and the part code), *except* when moving the thumb.  In assembly
>language, you can do a hack to try and determine which it is (since you
>want to just return for thumb actions, anyway), by looking at the
>supposed "theControl" argument and seeing if it is the handle to your
>control.  This is not certain, since the garbage on the stack could
>possibly have the same value you are looking for. 
>

Another way to solve this is to note that a control defproc can also handle
tracking (although the default scroll bar defproc does nothing).  If -1 is
stored in the contrlAction field of the scroll bar, then the defproc will be
called with the autoTrack message.  Since this is a defproc call, the
interface is the same for clicking in the arrows as dragging the thumb.

To get your action procedure to be called you must take the defproc handle
out of the scroll bar, save it, and install a handle to your new defproc.
(You should be able to use a "fake" handle created in global space.)

Your defproc simply calls the original defproc for every message except
autoTrack.  For the autoTrack message you simply do the appropriate thing in
your dialog.


(A bit of Macintosh trivia.  The reason why the thumb tracking proc takes
no parameters is because thumb tracking is done with a call to DragTheRgn,
and the actionProc accepted by DragTheRgn takes no parameters.)

-- 
Larry Rosenstein

Object Specialist
Apple Computer

AppleLink: Rosenstein1
UUCP:  {sun, voder, nsc, mtxinu, dual}!apple!lsr
CSNET: lsr@Apple.CSNET