[comp.sys.mac.programmer] Odd scrollbar behavior with TrackControl

alexis@ccnysci.UUCP (Alexis Rosen) (10/22/88)

In the last week I built a few utilities to make my life easier. They are not
real complicated- they don't have event loops, for example. I didn't expect
much trouble, and indeed for the most part everything went smoothly. There
was one big problem, however. For the help screen I put up, I wanted a working
scrollbar. So I built a DLOG & DITL & CNTL, and that seemed to work okay.
Then I wrote this bit of code to handle thumb dragging (before I did the
ActionProc for the scroll arrows):
WHILE iNo <> 1 DO BEGIN
 ModalDialog(NIL, iNo);
 IF iNo = 2 THEN BEGIN
   TEScroll(0, -tx^^.lineHeight * (GetCtlValue(ControlHandle(item)) - pos),tx);
   pos := GetCtlValue(ControlHandle(item))
   END
 END

(BTW, this is in LSP 1.11)

Everything still worked fine. Except- When I dragged the thumb, it didn't
drag a grey outline of the thumb the way it ordinarily does. It drew a two
pixel thick box that was inset one pixel from the regular thumb, and dragged
that around. This was weird, but it didn't bother me much.

What did bother me was the crash I kept getting when I defined an ActionProc
for the scrollbar control. I said:
  SetCtlAction(ControlHandle(item), @Scroller);
just before starting the ModalDialog loop. Scroller is a procedure that handles
clicks in the arrows and grey regions. The wierd thing is that the ActionProc
worked just fine. It did everything it was supposd to. BUT- now, the instant
I clicked on the thumb, the machine would crash. The debugger showed me that
when I was clicking in the thumb, my ActionProc was passed a bad ControlHandle.
Clicks elsewhere passed the correct handle.

This was so annoying that I skipped ModalDialog and did everything in a
window. No luck. Calling FindControl and TrackControl myself didn't improve
things at all. In the end, I brute-forced it by saying
IF TestControl(scrl, evnt.where) = inThumb THEN
  i := TrackControl(ctrl, evnt.where, NIL)
ELSE
  i := TrackControl(ctrl, evnt.where, Pointer(-1));

which means that if it's in the thumb, don't do the ActionProc, otherwise
go do it.

Does anyone have any idea what's going on???

----
Alexis Rosen                       alexis@dasys1.UUCP  or  alexis@ccnysci.UUCP
Writing from                       {allegra,philabs,cmcl2}!phri\
The Big Electric Cat                                       uunet!dasys1!alexis
Public UNIX                           {portal,well,sun}!hoptoad/

ech@poseidon.ATT.COM (Edward C Horvath) (10/24/88)

From article <942@ccnysci.UUCP>, by alexis@ccnysci.UUCP (Alexis Rosen):
! What did bother me was the crash I kept getting when I defined an ActionProc
! for the scrollbar control. I said:
!   SetCtlAction(ControlHandle(item), @Scroller);
! just before starting the ModalDialog loop. Scroller is a procedure that handles
! clicks in the arrows and grey regions. The wierd thing is that the ActionProc
! worked just fine. It did everything it was supposd to. BUT- now, the instant
! I clicked on the thumb, the machine would crash. The debugger showed me that
! when I was clicking in the thumb, my ActionProc was passed a bad ControlHandle.

Read IM, p I-324 very carefully: the actionProc gets parameters EXCEPT when
the part number is the indicator (i.e. the thumb), in which case THERE ARE
NO PARAMETERS.

You're right, the "parameters" are junk.  Worse, when you return from your
actionProc, it will pop the nonexistent params off the stack, corrupting the
stack.  Good night, Irene...

So yes, you need two different action routines, and you have to pass the
control handle to the thumb-routine through a global.  Ugly, mate.

=Ned Horvath=

thecloud@dhw68k.cts.com (Ken McLeod) (10/24/88)

In article <942@ccnysci.UUCP> alexis@ccnysci.UUCP (Alexis Rosen) writes:
>Then I wrote this bit of code to handle thumb dragging (before I did the
>ActionProc for the scroll arrows):
>WHILE iNo <> 1 DO BEGIN
> ModalDialog(NIL, iNo);
> IF iNo = 2 THEN BEGIN
>   TEScroll(0, -tx^^.lineHeight * (GetCtlValue(ControlHandle(item)) - pos),tx);
>   pos := GetCtlValue(ControlHandle(item))
>   END
> END
>
>What did bother me was the crash I kept getting when I defined an ActionProc
>for the scrollbar control. I said:
>  SetCtlAction(ControlHandle(item), @Scroller);
>just before starting the ModalDialog loop. Scroller is a procedure that handles
>clicks in the arrows and grey regions. The wierd thing is that the ActionProc
>worked just fine. It did everything it was supposd to. BUT- now, the instant
>I clicked on the thumb, the machine would crash. The debugger showed me that
>when I was clicking in the thumb, my ActionProc was passed a bad ControlHandle.
>Clicks elsewhere passed the correct handle.

  I had this happen to me also, using LSP 1.11a, when converting some code
that had worked just fine in the old System 3.2 days. In my case, I hadn't
declared my actionProc to have any arguments! Oops.

  You didn't post your "Scroller" procedure, so my guess is this: your
actionProc needs to declare its arguments (see IM vol 1 p 324).

PROCEDURE Scroller(theControl:ControlHandle; partCode:integer);
BEGIN
  {handle text scrolling}
END;

 rather than

PROCEDURE Scroller;
BEGIN
END; {wrong!}

 If the arguments aren't declared, you'll get garbage instead of the
correct ControlHandle.
 
 Hope this was helpful...


-- 
==========      .......     ===========================================
Ken McLeod     :.     .:    uucp: {spsd, zardoz, felix}!dhw68k!thecloud
==========    :::.. ..:::   InterNet: thecloud@dhw68k.cts.com
                 ////       ===========================================

alexis@ccnysci.UUCP (Alexis Rosen) (10/25/88)

Thanks to Ned Horvath (and Dave Platt, who answered by mail) for pointing out
this TrackControl oddity to me. I'm sure I knew about it in 1984 when I first
read IM...  I just wonder what other little details I've forgotten. :-(

I am still mystified by the weird thumb highlighting, though. It is totally
independant of the ActionProc (it manifested even before I wrote the Action-
Proc...) What happens is that instead of draging around a black box the same
size as the thumb & with one pixel borders, it drags around a box smaller than
the thumb by one pixel on each side, with borders TWO pixels wide. Has anyone
ever seen this kind of behavior before?

Thanks
----
Alexis Rosen                       alexis@dasys1.UUCP  or  alexis@ccnysci.UUCP
Writing from                       {allegra,philabs,cmcl2}!phri\
The Big Electric Cat                                       uunet!dasys1!alexis
Public UNIX                           {portal,well,sun}!hoptoad/

alexis@ccnysci.UUCP (Alexis Rosen) (10/26/88)

Ken McLeod recently responded to my original query (no, I'm not going to quote
two pages.)

Unfortunately, he erred in exactly the opposite direction that I did. I first
said, "I'm using an ActionProc, and its arguments are sometimes garbage." Ken
responds "Declare you arguments explicitly." That's exactly what I was doing,
and that's why I was crashing.

In fact, ActionProcs take EITHER two args (normal case) or none, for "dial
indicators." That's one ugly interface. Yuck. (Wonder how NeXT does it ;-)

----
Alexis Rosen                       alexis@dasys1.UUCP  or  alexis@ccnysci.UUCP
Writing from                       {allegra,philabs,cmcl2}!phri\
The Big Electric Cat                                       uunet!dasys1!alexis
Public UNIX                           {portal,well,sun}!hoptoad/

gandreas@umn-d-ub.D.UMN.EDU (Glenn Andreas) (10/27/88)

In article <953@ccnysci.UUCP> alexis@ccnysci.UUCP (Alexis Rosen) writes:
>
>Ken McLeod recently responded to my original query (no, I'm not going to quote
>two pages.)
>
>Unfortunately, he erred in exactly the opposite direction that I did. I first
>said, "I'm using an ActionProc, and its arguments are sometimes garbage." Ken
>responds "Declare you arguments explicitly." That's exactly what I was doing,
>and that's why I was crashing.
>
>In fact, ActionProcs take EITHER two args (normal case) or none, for "dial
>indicators." That's one ugly interface. Yuck. (Wonder how NeXT does it ;-)
>
>----
>Alexis Rosen                       alexis@dasys1.UUCP  or  alexis@ccnysci.UUCP


How about just skipping the explicit tracking call all together?  I was a DA
recently that needed a scroll bar, so I though, no problem.  However, any
routine used as a ProcPtr needed to be scoped globallly (i.e., it can't be a
nested procedure, the static link throws everything off).  But, I needed to
get some information that was with the DA, and thus passed to the main
routine.  But you can't use global variables with DA's, so there was no easy
way to get information between the ActionProc and the main routine (well,
you could probably use the control's RefCon, but I said easy).  So what I
did was do my own TrackControl, and the whole thing looked clearer than
using TrackControl with and ActionProc.  Basically, I did the following:

	Get the part hit in the control.
	if the part hit = inThumb then
		TrackControl with no Action Proc
	else while part first hit = where the mouse now is and still down do
		case part hit of
		up : Scroll down one
		down : Scroll up one
		pageUp : Scroll down one page
		pageDown : Scroll up one page

Or something to this effect (I don't have the code nearby to be able to
quote).  The scroll routine took the amount and then updated the control by
that amount, checking min & max, etc - basically I did the work of
TrackControl, and if I get around to this, I will code this up as a simple
procedure that I can reuse.  This can go with my SetDialogItemValue and
GetDialogItemValue routines that I use all the time.  These could be good
candidates for the code sample library that was once talked about here.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
= "Whether you like it, or don't like it, sit   | - gandreas@ub.d.umn.edu - =
=  back and take a look at it, because it's the |   Glenn Andreas           =
=  best going today!  WOOOOoooo!" - Ric Flair   |                           =
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

thecloud@dhw68k.cts.com (Ken McLeod) (10/28/88)

In article <953@ccnysci.UUCP> alexis@ccnysci.UUCP (Alexis Rosen) writes:
>Unfortunately, he erred in exactly the opposite direction that I did. I first
>said, "I'm using an ActionProc, and its arguments are sometimes garbage." Ken
>responds "Declare you arguments explicitly." That's exactly what I was doing,
>and that's why I was crashing.

 Sorry for the confusion... I must have misread your original post. If
you've set up an if-else construct to filter out "inThumb" from the other
part codes, you can call TrackControl with the appropriate one of your
2 actionProcs (the one with NO args). Of course, your control handle
needs to be defined globally, since it can't be passed to that actionProc.

 As for the weirdness with the outline that gets dragged, is it possible
that 1) your control handle is getting trashed somehow as large amounts
of memory are moved around during the actionProc? You might try explicitly
locking the control handle before calling TrackControl with it to see if
that makes a difference. Or 2) the scroll bar CDEF itself might have gotten
munged? Does this occur with different Systems active? (Or 3) ????)

>In fact, ActionProcs take EITHER two args (normal case) or none, for "dial
>indicators." That's one ugly interface. Yuck. (Wonder how NeXT does it ;-)

 You're right --- it's not too pretty. :-(  I've never needed to draw
anything *while* the thumb was being dragged, and therefore have never
had 2 actionProcs at the same time, so guess I never noticed it before.
("Two at the same time? That's bigamy!")
-- 
==========      .......     ===========================================
Ken McLeod     :.     .:    uucp: {spsd, zardoz, felix}!dhw68k!thecloud
==========    :::.. ..:::   InterNet: thecloud@dhw68k.cts.com
                 ////       ===========================================