home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / apps.to.go / DTS.Lib / CtlHandler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-14  |  37.4 KB  |  1,278 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        ctlhandler.c
  6. ** Written by:  Eric Soldan
  7. **
  8. ** Copyright © 1991-1993 Apple Computer, Inc.
  9. ** All rights reserved.
  10. */
  11.  
  12. /* You may incorporate this sample code into your applications without
  13. ** restriction, though the sample code has been provided "AS IS" and the
  14. ** responsibility for its operation is 100% yours.  However, what you are
  15. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  16. ** after having made changes. If you're going to re-distribute the source,
  17. ** we require that you make it clear in the source that the code was
  18. ** descended from Apple Sample Code, but that you've made changes. */
  19.  
  20. /* This code implements the new 7.0 human-interface standards for both
  21. ** TextEdit and List controls.  These standards include the following features:
  22. **
  23. ** 1) Tabbing between TextEdit and List controls within a window.
  24. ** 2) Displaying what item is active.  The active TextEdit item is indicated
  25. **    by either a blinking caret, or a selection range.
  26. ** 3) List positioning via the keyboard.  Entries on the keyboard automatically
  27. **    select and display the closest List item.  Also, the up and down arrows
  28. **    scroll through the list.
  29. ** 4) Window scrollbars are handled.
  30. */
  31.  
  32.  
  33.  
  34. /*****************************************************************************/
  35.  
  36.  
  37.  
  38. #include "DTS.Lib2.h"
  39. #include "DTS.Lib.protos.h"
  40.  
  41. #include "ListControlProcs.h"
  42. #include "TextEditControlProcs.h"
  43.  
  44. #ifndef __RESOURCES__
  45. #include <Resources.h>
  46. #endif
  47.  
  48. static void        OpenActionWindow(OSType sftype);
  49. static short    HandleScrollEvent(WindowPtr window, EventRecord *event);
  50.  
  51.  
  52.  
  53. /*****************************************************************************/
  54.  
  55.  
  56.  
  57. extern short        gBeginUpdateNested;
  58. extern Handle        gPopupProc;
  59. extern OSErr        gDialogErr;
  60.  
  61. short                gDataCtl = rDataCtl;
  62.  
  63. static FileRecHndl    gFrHndl;
  64. static Rect            gScrollRct;
  65. static Point        gKeepOrg;
  66. static Boolean        gVert;
  67.  
  68. static pascal void    ScrollActionProc(ControlHandle scrollCtl, short part);
  69. static void            ScrollTheContent(WindowPtr window, short h, short v);
  70. static short        GetCtlPosition(ControlHandle ctl);
  71.  
  72.  
  73.  
  74. /*****************************************************************************/
  75. /*****************************************************************************/
  76. /*****************************************************************************/
  77.  
  78.  
  79.  
  80. /* This function converts a control number to a control handle.  The function
  81. ** simply walks the window's control list counting down until it has reached
  82. ** the right control number.  It also returns the number of controls traversed.
  83. ** While often this will be the same as the control number passed in, if the
  84. ** number passed in is greater than the number of controls in the list, then
  85. ** the number returned is the number of controls in the list. */
  86.  
  87. /* NOTE: Additional support for control id's has been added.  To store the control id (cid),
  88. ** the control handle is grown, and the cid is stored after the control title.  This means
  89. ** that you can't directly call SetCTitle without losing the cid, as SetCTitle resizes the
  90. ** control handle.  You should instead call SetStyledCTitle, which preserves the cid.
  91. ** For backwards compatibility, CNum2Ctl and Ctl2CNum support both the old-style control
  92. ** numbers and the new-style control id's.  While backwards compatibility may be a good
  93. ** thing, what this means is that you have to assign your cid's so that the value is greater
  94. ** than the number of controls in the window. */
  95.  
  96. #pragma segment Controls
  97. short    CNum2Ctl(WindowPtr window, short ctlNum, ControlHandle *ctl)
  98. {
  99.     short    numCtls, cid;
  100.  
  101.     *ctl = nil;
  102.     if (!ctlNum) return(0);
  103.  
  104.     cid = ctlNum;    /* Caller may have actually passed us a cid. */
  105.  
  106.     *ctl = ((WindowPeek)window)->controlList;
  107.     for (numCtls = 1; --ctlNum;  ++numCtls) {
  108.         if (!*ctl) {
  109.             --numCtls;
  110.             break;
  111.         }
  112.         if (GetControlID(*ctl) == cid) break;
  113.         *ctl = (**ctl)->nextControl;
  114.     }
  115.  
  116.     return(numCtls);
  117. }
  118.  
  119.  
  120.  
  121. /*****************************************************************************/
  122.  
  123.  
  124.  
  125. /* This function converts a control handle to a control number.  The function
  126. ** simply walks the window's control list and counts how many controls it
  127. ** has to traverse before finding the target control.  The smallest control
  128. ** number that can be returned is 1.  This makes control numbers similar to
  129. ** dialog item numbers. */
  130.  
  131. /* NOTE: Additional support for control id's has been added.  To store the control id (cid),
  132. ** the control handle is grown, and the cid is stored after the control title.  This means
  133. ** that you can't directly call SetCTitle without losing the cid, as SetCTitle resizes the
  134. ** control handle.  You should instead call SetStyledCTitle, which preserves the cid.
  135. ** For backwards compatibility, CNum2Ctl and Ctl2CNum support both the old-style control
  136. ** numbers and the new-style control id's.  While backwards compatibility may be a good
  137. ** thing, what this means is that you have to assign your cid's so that the value is greater
  138. ** than the number of controls in the window. */
  139.  
  140. #pragma segment Controls
  141. short    Ctl2CNum(ControlHandle ctl)
  142. {
  143.     ControlHandle    nextCtl;
  144.     short            ctlNum;
  145.  
  146.     if (!ctl)   return(0);
  147.     ctlNum = GetControlID(ctl);
  148.     if (ctlNum) return(ctlNum);
  149.  
  150.     nextCtl = ((WindowPeek)(*ctl)->contrlOwner)->controlList;
  151.     for (ctlNum = 0;;) {
  152.         if (!nextCtl) break;
  153.         ++ctlNum;
  154.         if (ctl == nextCtl) break;
  155.         nextCtl = (*nextCtl)->nextControl;
  156.     }
  157.     return(ctlNum);
  158. }
  159.  
  160.  
  161.  
  162. /*****************************************************************************/
  163.  
  164.  
  165.  
  166. /* This function reactivates the last active TextEdit or List control for
  167. ** the indicated window. */
  168.  
  169. #pragma segment Controls
  170. void    DoCtlActivate(WindowPtr window)
  171. {
  172.     ListHandle    list;
  173.     TEHandle    te, oldte;
  174.     WindowPtr    oldww;
  175.  
  176.     list = (*gclWindActivate)(window, false);
  177.     if (list) {
  178.         if ((*list)->rView.left < -8192)
  179.             BeginFrame(window);
  180.         else
  181.             BeginContent(window);
  182.         (*gclWindActivate)(window, true);        /* Reactivate the list. */
  183.         EndContent(window);                        /* Same as EndFrame().  */
  184.         return;
  185.     }
  186.  
  187.     oldte = (*gcteFindActive)(nil);
  188.     te    = (*gcteWindActivate)(window, false);
  189.  
  190.     if (oldte && (oldte != te)) {
  191.         oldww = (*oldte)->inPort;
  192.         if ((*oldte)->viewRect.left < -8192)
  193.             BeginFrame(oldww);
  194.         else
  195.             BeginContent(oldww);
  196.         (*gcteWindActivate)(oldww, true);
  197.         EndContent(oldww);
  198.     }
  199.     if (te) {
  200.         if ((*te)->viewRect.left < -8192)
  201.             BeginFrame(window);
  202.         else
  203.             BeginContent(window);
  204.         (*gcteWindActivate)(window, true);
  205.         EndContent(window);
  206.     }
  207. }
  208.  
  209.  
  210.  
  211. /*****************************************************************************/
  212.  
  213.  
  214.  
  215. /* This function returns all the checkBox values into the dsignated array.
  216. ** The function walks the control list, and when it finds a checkBox control,
  217. ** it gets the control value and places it in the next position in the array.
  218. ** This allows a single call to retrieve all the checkBox values at once. */
  219.  
  220. #pragma segment Controls
  221. void    GetCheckBoxValues(WindowPtr window, Boolean checkBoxVal[])
  222. {
  223.     ControlHandle    nextCtl;
  224.     short            checkBoxIndx;
  225.  
  226.     nextCtl = ((WindowPeek)window)->controlList;
  227.     for (checkBoxIndx = 0;;) {
  228.         if (!nextCtl) return;
  229.         if (GetButtonVariant(nextCtl) == checkBoxProc)
  230.             checkBoxVal[checkBoxIndx++] = GetControlValue(nextCtl);
  231.         nextCtl = (*nextCtl)->nextControl;
  232.     }
  233. }
  234.  
  235.  
  236.  
  237. /*****************************************************************************/
  238.  
  239.  
  240.  
  241. /* This function returns which radio button is selected for a particular
  242. ** family of radio buttons.  It finds the radio button of the target family
  243. ** with the lowest control number and it subtracts this number from the
  244. ** selected radio button of the same family.  This gives a relative radio
  245. ** button number as a return result.  This way the position of the family
  246. ** of radio buttons can change in the window and the return result is the
  247. ** same.  The family number is stored in the control's refCon field. */
  248.  
  249. #pragma segment Controls
  250. short    GetRadioButtonChoice(WindowPtr window, short famNum)
  251. {
  252.     ControlHandle    nextCtl;
  253.     short            firstInFam, cnum, chosen;
  254.  
  255.     nextCtl = ((WindowPeek)window)->controlList;
  256.     for (firstInFam = chosen = 0;;) {
  257.         if (!nextCtl) {
  258.             if (!chosen) return(-1);
  259.                 /* If a proper radio button family was passed in, this can't
  260.                 ** happen.  The -1 is an error that indicates that the
  261.                 ** requested family didn't exist, or that there was no selected
  262.                 ** radio of the requested family. */
  263.             return(chosen - firstInFam);
  264.         }
  265.         if (GetButtonVariant(nextCtl) == radioButProc) {
  266.             if (GetControlReference(nextCtl) == famNum) {
  267.                 cnum = Ctl2CNum(nextCtl);
  268.                 if (!firstInFam)
  269.                     firstInFam = cnum;
  270.                 else {
  271.                     if (firstInFam > cnum)
  272.                         firstInFam = cnum;
  273.                 }
  274.                 if (GetControlValue(nextCtl)) chosen = cnum;
  275.             }
  276.         }
  277.         nextCtl = (*nextCtl)->nextControl;
  278.     }
  279. }
  280.  
  281.  
  282.  
  283. /*****************************************************************************/
  284.  
  285.  
  286.  
  287. /* This function currently handles events for TextEdit, List, and button
  288. ** controls in a window.  It also handles the window scrollbars and
  289. ** scrolling of the window. */
  290.  
  291. #pragma segment Controls
  292. short    IsCtlEvent(WindowPtr window, EventRecord *event, ControlHandle *retCtl, short *retAction)
  293. {
  294.     RgnHandle            docScroller, docFrame, oldClip, newClip;
  295.     TEHandle            te, oldte, teNext;
  296.     ListHandle            list, oldlist, listNext;
  297.     ControlHandle        xxx, activeCtl, teCtl, listCtl, nextCtl, newCtl, dataCtl, cc;
  298.     short                ctlNum, key, modifiers, mode, action, dir, pass, visMode;
  299.     short                thisNum, teNum, listNum, i, oldVal, newVal, dpass, part;
  300.     Boolean                hitFrame, hitScrollBar, tracked, hasBalloon, didPopup, didKey;
  301.     CTEDataHndl            teData;
  302.     CLDataHndl            listData;
  303.     EventRecord            evt;
  304.     WindowPtr            ww;
  305.     ControlStyleInfo    cinfo;
  306.     short                targetChr, targetMod;
  307.     Str255                dataCtlTitle;
  308.     OSType                sftype, sftypeNW;
  309.     Rect                org;
  310.     Point                org2;
  311.     Point                mouseLoc;
  312. #ifndef powerc
  313.     FileRecHndl            ff;
  314.     RgnHandle            rgn;
  315. #endif
  316.  
  317.     pass = 0;
  318.     sftypeNW = 0;
  319.  
  320.     if (!retCtl)    retCtl    = &xxx;
  321.     if (!retAction) retAction = &action;
  322.  
  323.     *retCtl    = nil;
  324.     *retAction = 0;
  325.  
  326.     evt = *event;
  327.  
  328.     if (evt.what == nullEvent) {
  329.         mouseLoc = GetGlobalMouse();
  330.         window   = FrontWindowOfType(kwIsModalDialog, true);
  331.  
  332. #ifndef powerc
  333.         if (window) {
  334.             ff = (FileRecHndl)GetWRefCon(window);
  335.             if (ff) {
  336.                 if ((*ff)->fileState.sfType == '6hlp') {
  337.                     for (; (window = GetNextWindow(window, 0)) != nil;) {
  338.                         if (((WindowPeek)window)->visible) break;
  339.                     }
  340.                 }
  341.             }
  342.         }
  343. #endif
  344.  
  345.         if (!window) {
  346.             part = FindWindow(mouseLoc, &window);
  347. #ifndef powerc
  348.             ww = GetNextWindow(nil, '6hlp');
  349.             if (ww) {
  350.                 if (ww == window) {        /* We found the help window -- that's bad. */
  351.                     CopyRgn(((WindowPeek)ww)->strucRgn, rgn = NewRgn());
  352.                     OffsetRgn(((WindowPeek)ww)->strucRgn, 16384, 0);
  353.                     OffsetRgn(((WindowPeek)ww)->contRgn,  16384, 0);
  354.                     CalcVisBehind((WindowPeek)ww, rgn);
  355.                     DisposeRgn(rgn);
  356.                     part = FindWindow(mouseLoc, &window);
  357.                     OffsetRgn(((WindowPeek)ww)->strucRgn, -16384, 0);
  358.                     OffsetRgn(((WindowPeek)ww)->contRgn,  -16384, 0);
  359.                     CalcVisBehind((WindowPeek)ww, ((WindowPeek)ww)->strucRgn);
  360.                 }
  361.             }
  362. #endif
  363.             if (part == inContent)
  364.                 if (!(((WindowPeek)window)->hilited))
  365.                     window = nil;
  366.         }
  367.         hasBalloon = false;
  368.         if (IsDAWindow(window)) window = nil;
  369.         if (window) {
  370.             if (PtInRgn(mouseLoc, ((WindowPeek)window)->contRgn)) {
  371.                 SetPort(window);
  372.                 org = window->portRect;
  373.  
  374.                 docFrame = DoCalcFrameRgn(window);
  375.                 hitFrame = PtInRgn(mouseLoc, docFrame);
  376.                 DisposeRgn(docFrame);
  377.  
  378.                 if (hitFrame) {
  379.                     BeginFrame(window);        /* This sets the origin for the frame. */
  380.                     EndFrame(window);        /* This DOESN'T reset the origin for the frame, so the origin is now set correctly. */
  381.                     hasBalloon = ControlBalloonHelp(window, event->modifiers, mouseLoc);
  382.                 }
  383.                 else {
  384.                     BeginContent(window);    /* This sets the origin for the content. */
  385.                     EndContent(window);        /* This DOESN'T reset the origin for the content, so the origin is now set correctly. */
  386.                     hasBalloon = ControlBalloonHelp(window, event->modifiers, mouseLoc);
  387.                 }
  388.                 SetOrigin(org.left, org.top);
  389.             }
  390.         }
  391.         if (!hasBalloon) {
  392. #ifndef powerc
  393.             ww = GetNextWindow(nil, '6hlp');
  394.             if (ww) DisposeOneWindow(ww, kClose);
  395. #endif
  396.             ControlBalloonHelp(nil, event->modifiers, mouseLoc);
  397.         }
  398.         return(0);
  399.     }
  400.  
  401.     if (!window) return(0);
  402.  
  403.     org = window->portRect;
  404.  
  405.     if (evt.what == mouseDown) {
  406.  
  407.         docScroller = DoCalcScrollRgn(window);
  408.         hitFrame    = PtInRgn(evt.where, docScroller);
  409.         DisposeRgn(docScroller);
  410.         if (hitFrame) return(HandleScrollEvent(window, &evt));
  411.             /* If window scrollbar is clicked on, handle the window scroll event. */
  412.  
  413.         docFrame = DoCalcFrameRgn(window);
  414.         hitFrame = PtInRgn(evt.where, docFrame);
  415.         DisposeRgn(docFrame);
  416.  
  417.         evt.where = event->where;
  418.         if (hitFrame)
  419.             BeginFrame(window);
  420.         else
  421.             BeginContent(window);
  422.         GlobalToLocal(&evt.where);
  423.  
  424.         (*gcteCtlHit)();    /* Clear CTECtl defProc's last hit CTECtl. */
  425.         (*gclCtlHit)();        /* Clear CLCtl defProc's last hit CLCtl. */
  426.  
  427.         if (WhichControl(evt.where, 0, window, retCtl)) {
  428.                 /* WhichControl also finds inactive controls.  We need this for scrollbars.
  429.                 ** If an inactive scrollbar is hit, we should activate the related
  430.                 ** TextEdit or List control. */
  431.  
  432.             hitScrollBar = IsScrollBar(*retCtl);
  433.                 /* The List controls and TextEdit controls may have scrollbars.
  434.                 ** Find out if a scrollbar was pressed, because it may belong
  435.                 ** to a TextEdit or List control. */
  436.  
  437.             part = FindControl(evt.where, window, retCtl);
  438.                 /* WhichControl doesn't call the scrollProc.  FindControl does.
  439.                 ** We need it called so we can determine below if a TextEdit or
  440.                 ** List control was hit.  CTECtlHit() and CLCtlHit() return
  441.                 ** the last hit respective control. */
  442.  
  443.             ctlNum = Ctl2CNum(*retCtl);
  444.  
  445.             if ((hitScrollBar) || ((*gcteCtlHit)())) {
  446.                     /* This test is for speed.  CTEClick would find out if a TextEdit
  447.                     ** control handled the mouse click, but not as fast as we would
  448.                     ** like.  The above test determines if it is worth investigating. */
  449.  
  450.                 cc = CTEFindCtl(window, event, &te, nil);
  451.                 if (cc) {
  452.  
  453.                     if ((*cc)->contrlHilite != 255) {
  454.                         ww = CTETargetInfo(&oldte, nil);
  455.                         SetOrigin(org.left, org.top);
  456.                         EndContent(window);
  457.  
  458.                         if ((oldte) && (te != oldte)) {
  459.                             if ((*oldte)->viewRect.left < -8192)
  460.                                 BeginFrame(ww);
  461.                             else
  462.                                 BeginContent(ww);
  463.                             (*gcteActivate)(false, oldte);
  464.                             SetOrigin(org.left, org.top);
  465.                             EndContent(ww);
  466.                         }
  467.                         list = (*gclFindActive)(window);
  468.                         if (list) {
  469.                             cc = CLViewFromList(list);
  470.                             listData = (CLDataHndl)(*cc)->contrlData;
  471.                             mode     = (*listData)->mode;
  472.                             if (mode & (clShowActive | clKeyPos)) {
  473.                                 if ((*list)->rView.left < -8192)
  474.                                     BeginFrame(window);
  475.                                 else
  476.                                     BeginContent(window);
  477.                                 (*gclActivate)(false, list);
  478.                                 SetOrigin(org.left, org.top);
  479.                                 EndContent(window);
  480.                             }
  481.                         }
  482.                         if (evt.where.h < -8192)
  483.                             BeginFrame(window);
  484.                         else
  485.                             BeginContent(window);
  486.                     }
  487.  
  488.                     if ((*gcteClick)(window, event, retAction)) {    /* If click for TE control... */
  489.                         if (*retAction == -1) {
  490.                             *retCtl = (*gcteViewFromTE)(CTEFindActive(window));
  491.                             teData  = (CTEDataHndl)(**retCtl)->contrlData;
  492.                             mode    = (*teData)->mode;
  493.                             if (!(mode & cteTwoStep))
  494.                                 (*gcteClick)(window, event, retAction);
  495.                         }
  496.                         SetOrigin(org.left, org.top);
  497.                         EndContent(window);
  498.                         return(ctlNum);
  499.                     }
  500.                 }
  501.             }
  502.  
  503.             if ((hitScrollBar) || ((*gclCtlHit)())) {
  504.                     /* This test is for speed.  CLClick would find out if a List
  505.                     ** control handled the mouse click, but not as fast as we would
  506.                     ** like.  The above test determines if it is worth investigating. */
  507.  
  508.                 cc = CLFindCtl(window, event, &list, nil);
  509.                 if (cc) {
  510.                     if ((*cc)->contrlHilite != 255) {
  511.                         oldlist = CLFindActive(window);
  512.                         SetOrigin(org.left, org.top);
  513.                         EndContent(window);
  514.                         if ((oldlist) && (list != oldlist)) {
  515.                             if ((*oldlist)->rView.left < -8192)
  516.                                 BeginFrame(window);
  517.                             else
  518.                                 BeginContent(window);
  519.                             (*gclActivate)(false, oldlist);
  520.                             SetOrigin(org.left, org.top);
  521.                             EndContent(window);
  522.                         }
  523.                         if (list) {
  524.                             cc = CLViewFromList(list);
  525.                             listData = (CLDataHndl)(*cc)->contrlData;
  526.                             mode     = (*listData)->mode;
  527.                             if (mode & (clShowActive | clKeyPos)) {
  528.                                 te = (*gcteFindActive)(window);
  529.                                 if (te) {
  530.                                     if ((*te)->viewRect.left < -8192)
  531.                                         BeginFrame(window);
  532.                                     else
  533.                                         BeginContent(window);
  534.                                     (*gcteActivate)(false, te);
  535.                                     SetOrigin(org.left, org.top);
  536.                                     EndContent(window);
  537.                                 }
  538.                             }
  539.                         }
  540.                         if (evt.where.h < -8192)
  541.                             BeginFrame(window);
  542.                         else
  543.                             BeginContent(window);
  544.                     }
  545.  
  546.                     if ((*gclClick)(window, event, retAction)) {    /* If click for List control... */
  547.                         if (*retAction == -1) {        /* Just activated a List control... */
  548.                             *retCtl  = (*gclViewFromList)((*gclFindActive)(window));
  549.                             listData = (CLDataHndl)(**retCtl)->contrlData;
  550.                             mode     = (*listData)->mode;
  551.                             if (!(mode & clTwoStep))
  552.                                 (*gclClick)(window, event, retAction);
  553.                         }
  554.                         SetOrigin(org.left, org.top);
  555.                         EndContent(window);
  556.                         return(ctlNum);
  557.                     }
  558.                 }
  559.             }
  560.  
  561.             didPopup = tracked = false;
  562.             WhichControl(evt.where, 0, window, retCtl);
  563.             if (gPopupProc) {        /* The popup control does not handle negative coords. */
  564.                 if (StripAddress((**retCtl)->contrlDefProc) == StripAddress(gPopupProc)) {
  565.                     didPopup = true;
  566.                     org2.h = window->portRect.left;
  567.                     org2.v = window->portRect.top;
  568.                     GetClip(oldClip = NewRgn());
  569.                     RectRgn(newClip = NewRgn(), &(window->portRect));
  570.                     SectRgn(newClip, oldClip, newClip);
  571.                     SetOrigin(0, 0);
  572.                     OffsetRgn(newClip, -org2.h, -org2.v);
  573.                     SetClip(newClip);
  574.                     OffsetRect(&((**retCtl)->contrlRect), -org2.h, -org2.v);
  575.                     oldVal  = (**retCtl)->contrlValue;
  576.                     UseControlStyle(*retCtl);
  577.                     cinfo.trackProc = nil;
  578.                     GetControlStyle(*retCtl, &cinfo);
  579.                     if (cinfo.trackProc)
  580.                         tracked = (*cinfo.trackProc)(*retCtl, part, &evt);
  581.                     else
  582.                         tracked = TrackControl(*retCtl, evt.where, (ControlActionUPP)(-1));
  583.                     newVal = (**retCtl)->contrlValue;
  584.                     UseControlStyle(nil);
  585.                     ctlNum = 0;
  586.                     if (oldVal != newVal) {
  587.                         tracked = true;
  588.                         ctlNum  = Ctl2CNum(*retCtl);
  589.                     }
  590.                     OffsetRect(&((**retCtl)->contrlRect), org2.h, org2.v);
  591.                     SetOrigin(org2.h, org2.v);
  592.                     SetClip(oldClip);
  593.                     DisposeRgn(oldClip);
  594.                     DisposeRgn(newClip);
  595.                     DoDraw1Control(*retCtl, false);
  596.                 }
  597.             }
  598.  
  599.             *retAction = 0;
  600.  
  601.             if (!didPopup) {
  602.                 FindControl(evt.where, window, retCtl);
  603.                 if (!*retCtl) {
  604.                     SetOrigin(org.left, org.top);
  605.                     EndContent(window);
  606.                     return(ctlNum);
  607.                 }
  608.  
  609.                 WhichControl(evt.where, evt.when, window, nil);
  610.                     /* WhichControl places the hit control in the global gWhichCtl.
  611.                     ** This global is used by CCIconCtl to determine double-clicks.
  612.                     ** Double-clicking is also calculated by WhichControl.  The global
  613.                     ** gWhichCtlDbl is set true if the control was double-clicked on.
  614.                     ** We call WhichControl with the click time just prior to tracking
  615.                     ** the control.  When a non-0 tick is passed in, it compares the found
  616.                     ** control against the last found control, and the tick against the last
  617.                     ** tick.  The globals are set accordingly. */
  618.  
  619.                 oldVal = (**retCtl)->contrlValue;
  620.                 UseControlStyle(*retCtl);
  621.                 cinfo.trackProc = nil;
  622.                 GetControlStyle(*retCtl, &cinfo);
  623.                 if (cinfo.trackProc)
  624.                     tracked = (*cinfo.trackProc)(*retCtl, part, &evt);
  625.                 else
  626.                     tracked = TrackControl(*retCtl, evt.where, (ControlActionUPP)(-1));
  627.                 UseControlStyle(nil);
  628.             }
  629.     
  630.             if (tracked) {                    /* Handle other controls. */
  631.                 switch(GetButtonVariant(*retCtl)) {
  632.                     case pushButProc:
  633.                         break;
  634.                     case checkBoxProc:
  635.                         SetStyledCtlValue(*retCtl, GetControlValue(*retCtl) ^ 1);
  636.                                 /* Toggle checkBox value. */
  637.                         break;
  638.                     case radioButProc:
  639.                         nextCtl = ((WindowPeek)window)->controlList;
  640.                             /* The below loop walks the control list for the window and
  641.                             ** finds radio buttons of the correct family number.  If
  642.                             ** the found radio button is the one that was clicked on,
  643.                             ** the value is set true, otherwise it is set false. */
  644.                         for (; nextCtl; nextCtl = (*nextCtl)->nextControl) {
  645.                             if (GetButtonVariant(nextCtl) == radioButProc)
  646.                                 if (GetControlReference(nextCtl) == GetControlReference(*retCtl))
  647.                                     SetStyledCtlValue(nextCtl, (nextCtl == *retCtl));
  648.                         }
  649.                         break;
  650.                 }
  651.  
  652.                 newVal = (**retCtl)->contrlValue;
  653.  
  654.                 if (GetControlStyle(*retCtl, &cinfo)) {
  655.                     for (i = 1;; i += 6) {
  656.                         if (i >= cinfo.keyEquivs[0]) break;
  657.                         if (cinfo.keyEquivs[i] == (unsigned char)',') ++i;
  658.                         if (cinfo.keyEquivs[i] == (unsigned char)'\'')
  659.                             BlockMove(cinfo.keyEquivs + i + 1, (Ptr)&sftypeNW, sizeof(OSType));
  660.                         if (cinfo.keyEquivs[i] == (unsigned char)':') {
  661.                             targetChr = GetHexByte((char *)(cinfo.keyEquivs + i + 1));
  662.                             targetMod = GetHexByte((char *)(cinfo.keyEquivs + i + 2 + 1)) << 8;
  663.                             evt.what       = keyDown;
  664.                             evt.message    = targetChr;
  665.                             evt.modifiers &= 0x00FF;
  666.                             evt.modifiers |= (targetMod << 8);
  667.                             pass = 1;
  668.                             if (cinfo.keyEquivs[0] > i + 4)
  669.                                 if (cinfo.keyEquivs[i + 5] == '<')
  670.                                     pass = 0;
  671.                                         /* If delimiter is a <, then reprocess with
  672.                                         ** pass #0.  This could cause an infinite loop
  673.                                         ** if the targetEquiv is the same as what was
  674.                                         ** pressed.  The reason that this is done is if
  675.                                         ** the targetEquiv is different than the original
  676.                                         ** event, and we want to give non-te, non-list controls
  677.                                         ** a chance to process the equiv.  Normally the whole
  678.                                         ** purpose for this feature is to first notice that a
  679.                                         ** pass-0 control has an equiv, and then we want to pass
  680.                                         ** this key onto a te control. */
  681.                         }
  682.                     }
  683.                 }
  684.  
  685.                 if (oldVal != newVal) {
  686.                     *retAction = 3;
  687.                     oldVal -= (**retCtl)->contrlMin;
  688.                     newVal -= (**retCtl)->contrlMin;
  689.                     CNum2Ctl(window, -ctlNum, &dataCtl);
  690.                     if (dataCtl) {
  691.                         GetControlTitle(dataCtl, dataCtlTitle);
  692.                         switch (GetControlVariant(dataCtl)) {
  693.                             case 0:
  694.                                 for (dpass = 0; dpass < 2; ++dpass) {
  695.                                     i  = (dpass) ? newVal : oldVal;
  696.                                     i *= 7;
  697.                                     i += 2;
  698.                                     if (i <= dataCtlTitle[0] - 3) {
  699.                                         BlockMove(dataCtlTitle + i, &sftype, sizeof(OSType));
  700.                                         visMode = (dpass) ? kwStandardVis : kwHideAll;
  701.                                         DisplayControlSet(window, sftype, visMode);
  702.                                     }
  703.                                 }
  704.                                 break;
  705.                         }
  706.                     }
  707.                 }
  708.             }
  709.             else {
  710.                 *retCtl = nil;
  711.                 ctlNum = 0;
  712.             }
  713.  
  714.             SetOrigin(org.left, org.top);
  715.             EndContent(window);
  716.  
  717.             if (evt.what != keyDown) {
  718.                 if (sftypeNW) OpenActionWindow(sftypeNW);
  719.                 return(ctlNum);
  720.             }
  721.         }
  722.  
  723.         if (evt.what != keyDown) {
  724.             SetOrigin(org.left, org.top);
  725.             EndContent(window);
  726.             if (sftypeNW) OpenActionWindow(sftypeNW);
  727.             return(0);
  728.         }
  729.     }
  730.  
  731.     if ((evt.what == keyDown) || (evt.what == autoKey)) {        /* If event was keypress... */
  732.  
  733.         modifiers = evt.modifiers;
  734.         key       = evt.message & charCodeMask;
  735.         dir       = (modifiers & shiftKey) ? -1 : 1;
  736.  
  737.         if (key == chTab) {        /* If tab... */
  738.  
  739.             teNext    = nil;
  740.             listNext  = nil;
  741.             activeCtl = nil;
  742.  
  743.             list = (*gclFindActive)(window);
  744.             if (list) {
  745.                 activeCtl = (*gclViewFromList)(list);    /* Find what the active control is. */
  746.                 listData = (CLDataHndl)(*activeCtl)->contrlData;
  747.                 mode     = (*listData)->mode;
  748.                 if (!(mode & (clShowActive | clKeyPos)))
  749.                     activeCtl = nil;
  750.                         /* Find out if active List control supports key
  751.                         ** positioning and/or show active. */
  752.             }
  753.  
  754.             te = (*gcteFindActive)(window);
  755.             if (te)
  756.                 activeCtl = (*gcteViewFromTE)(te);
  757.  
  758.             if (!(teCtl = (*gcteNext)(window, &teNext, activeCtl, dir, true)))
  759.                 teCtl = (*gcteNext)(window, &teNext, nil, dir, true);
  760.                     /* Find the next TextEdit control from the active control. */
  761.  
  762.             listCtl = activeCtl;
  763.             for (; (listCtl = (*gclNext)(window, &listNext, listCtl, dir, true)) != nil;) {
  764.                 listData = (CLDataHndl)(*listCtl)->contrlData;
  765.                 mode     = (*listData)->mode;
  766.                 if (mode & (clShowActive | clKeyPos)) break;
  767.             }
  768.             if (!listCtl) {
  769.                 for (; (listCtl = (*gclNext)(window, &listNext, listCtl, dir, true)) != nil;) {
  770.                     listData = (CLDataHndl)(*listCtl)->contrlData;
  771.                     mode     = (*listData)->mode;
  772.                     if (mode & (clShowActive | clKeyPos)) break;
  773.                 }
  774.             }
  775.  
  776.             if ((teNext) || (listNext)) {
  777.  
  778.                 thisNum = GetCtlPosition(activeCtl);
  779.                 teNum   = GetCtlPosition(teCtl);
  780.                 listNum = GetCtlPosition(listCtl);
  781.  
  782.                 newCtl = activeCtl;
  783.                 if (dir == 1) {
  784.                     if (!teNum)   teNum   = 32767;
  785.                     if (!listNum) listNum = 32767;
  786.                     if (teNum   <= thisNum) teNum   += 16384;
  787.                     if (listNum <= thisNum) listNum += 16384;
  788.                     if (teNum < listNum) newCtl = teCtl;
  789.                     if (listNum < teNum) newCtl = listCtl;
  790.                 }
  791.                 else {
  792.                     if (!teNum)   teNum   = -32767;
  793.                     if (!listNum) listNum = -32767;
  794.                     if (teNum   >= thisNum) teNum   -= 16384;
  795.                     if (listNum >= thisNum) listNum -= 16384;
  796.                     if (teNum > listNum) newCtl = teCtl;
  797.                     if (listNum > teNum) newCtl = listCtl;
  798.                 }
  799.  
  800.                 if (activeCtl == newCtl) {
  801.                     if (newCtl == teCtl) {
  802.                         if ((*teNext)->viewRect.left < -8192)
  803.                             BeginFrame(window);
  804.                         else
  805.                             BeginContent(window);
  806.                         (*gcteActivate)(true, teNext);
  807.                         teData = (CTEDataHndl)(*teCtl)->contrlData;
  808.                         if ((*teData)->mode & cteTabSelectAll)
  809.                             (*gcteSetSelect)(0, (*teNext)->teLength, teNext);
  810.                                 /* If the "select all TextEdit text when tabbed into" bit is
  811.                                 ** set, then do that very thing. */
  812.                         SetOrigin(org.left, org.top);
  813.                         EndContent(window);
  814.                     }
  815.                     return(0);
  816.                 }
  817.  
  818.                 if (te) {            /* If old ctl is te, deactivate it. */
  819.                     if ((*te)->viewRect.left < -8192)
  820.                         BeginFrame(window);
  821.                     else
  822.                         BeginContent(window);
  823.                     (*gcteActivate)(false, te);
  824.                     SetOrigin(org.left, org.top);
  825.                     EndContent(window);
  826.                 }
  827.  
  828.                 if (list) {            /* If old ctl is list, deactivate it. */
  829.                     if ((*list)->rView.left < -8192)
  830.                         BeginFrame(window);
  831.                     else
  832.                         BeginContent(window);
  833.                     (*gclActivate)(false, list);
  834.                     SetOrigin(org.left, org.top);
  835.                     EndContent(window);
  836.                 }
  837.  
  838.                 if (newCtl == teCtl) {
  839.                     if ((*teNext)->viewRect.left < -8192)
  840.                         BeginFrame(window);
  841.                     else
  842.                         BeginContent(window);
  843.                     (*gcteActivate)(true, teNext);
  844.                     teData = (CTEDataHndl)(*teCtl)->contrlData;
  845.                     if ((*teData)->mode & cteTabSelectAll)
  846.                         (*gcteSetSelect)(0, (*teNext)->teLength, teNext);
  847.                             /* If the "select all TextEdit text when tabbed into" bit is
  848.                             ** set, then do that very thing. */
  849.                     SetOrigin(org.left, org.top);
  850.                     EndContent(window);
  851.                     return(Ctl2CNum(*retCtl = teCtl));
  852.                 }
  853.  
  854.                 if (newCtl == listCtl) {
  855.                     if ((*listNext)->rView.left < -8192)
  856.                         BeginFrame(window);
  857.                     else
  858.                         BeginContent(window);
  859.                     (*gclActivate)(true, listNext);
  860.                     SetOrigin(org.left, org.top);
  861.                     EndContent(window);        /* Remove the clipping. */
  862.                     return(Ctl2CNum(*retCtl = listCtl));
  863.                 }
  864.             }
  865.         }
  866.  
  867.         for (; pass < 3; ++pass) {
  868.             switch (pass) {
  869.                 case 0:
  870.                 case 2:
  871.                     if (ControlKeyEquiv(window, &evt, retCtl, ((pass) ? "\p031900,0D1900" :
  872.                                                                         "\p031900"))) {
  873.                         if ((**retCtl)->contrlRect.left < -8192)
  874.                             BeginFrame(window);
  875.                         else
  876.                             BeginContent(window);
  877.  
  878.                         cinfo.trackProc = nil;                    /* Give keystrokes a chance to "track".          */
  879.                         GetControlStyle(*retCtl, &cinfo);        /* This is really so there's symmetry between */
  880.                         if (cinfo.trackProc)                    /* mouseDowns and keystrokes.                  */
  881.                             if (!(*cinfo.trackProc)(*retCtl, part, &evt))
  882.                                 continue;
  883.  
  884.                         SelectButton(*retCtl);
  885.                         oldVal = GetControlValue(*retCtl);
  886.                         switch(GetButtonVariant(*retCtl)) {
  887.                             case pushButProc:
  888.                                 break;
  889.                             case checkBoxProc:
  890.                                 SetStyledCtlValue(*retCtl, GetControlValue(*retCtl) ^ 1);
  891.                                         /* Toggle checkBox value. */
  892.                                 break;
  893.                             case radioButProc:
  894.                                 nextCtl = ((WindowPeek)window)->controlList;
  895.                                     /* The below loop walks the control list for the window and
  896.                                     ** finds radio buttons of the correct family number.  If
  897.                                     ** the found radio button is the one that was clicked on,
  898.                                     ** the value is set true, otherwise it is set false. */
  899.                                 for (; nextCtl; nextCtl = (*nextCtl)->nextControl) {
  900.                                     if (GetButtonVariant(nextCtl) == radioButProc)
  901.                                         if (GetControlReference(nextCtl) == GetControlReference(*retCtl))
  902.                                             SetStyledCtlValue(nextCtl, (nextCtl == *retCtl));
  903.                                 }
  904.                                 break;
  905.                         }
  906.                         SetOrigin(org.left, org.top);
  907.                         EndContent(window);
  908.                         newVal = GetControlValue(*retCtl);
  909.                         if (oldVal != newVal) *retAction = 3;
  910.  
  911.                         if (!pass) {
  912.                             if (GetControlStyle(*retCtl, &cinfo)) {
  913.                                 for (i = 1;; i += 6) {
  914.                                     if (i >= cinfo.keyEquivs[0]) break;
  915.                                     if (cinfo.keyEquivs[i] == (unsigned char)',') ++i;
  916.                                     if (cinfo.keyEquivs[i] == (unsigned char)'\'')
  917.                                         BlockMove(cinfo.keyEquivs + i + 1, (Ptr)&sftypeNW, sizeof(OSType));
  918.                                     if (cinfo.keyEquivs[i] == (unsigned char)':') {
  919.                                         targetChr = GetHexByte((char *)(cinfo.keyEquivs + i + 1));
  920.                                         targetMod = GetHexByte((char *)(cinfo.keyEquivs + i + 2 + 1)) << 8;
  921.                                         evt.message    = targetChr;
  922.                                         evt.modifiers &= 0x00FF;
  923.                                         evt.modifiers |= (targetMod << 8);
  924.                                         if (cinfo.keyEquivs[0] > i + 4)
  925.                                             if (cinfo.keyEquivs[i + 5] == '<')
  926.                                                 --pass;
  927.                                                     /* If delimiter is a <, then reprocess with pass #0.
  928.                                                     ** This could cause an infinite loop if the targetEquiv
  929.                                                     ** is the same as what was pressed.  The reason that this
  930.                                                     ** is done is if the targetEquiv is different than the
  931.                                                     ** original event, and we want to give non-te, non-list controls
  932.                                                     ** a chance to process the equiv.  Normally the whole purpose for
  933.                                                     ** this feature is to first notice that a pass-0 control has an
  934.                                                     ** equiv, and then we want to pass this key onto a te control. */
  935.                                         i = 999;
  936.                                     }
  937.                                 }
  938.                                 if (i >= 999) continue;
  939.                             }
  940.                         }
  941.  
  942.                         if (sftypeNW) OpenActionWindow(sftypeNW);
  943.                         return(Ctl2CNum(*retCtl));
  944.                     }
  945.  
  946.                     break;
  947.                 case 1:
  948.                     if (evt.modifiers & cmdKey) break;            /* Don't allow command keys to go to te and list controls. */
  949.                     te = (*gcteFindActive)(window);
  950.                     if (te) {                                    /* If TextEdit control is active... */
  951.                         if ((*te)->viewRect.left < -8192)
  952.                             BeginFrame(window);
  953.                         else
  954.                             BeginContent(window);
  955.                         *retAction = (*gcteKey)(window, &evt);    /* Allow processing by TE control. */
  956.                         SetOrigin(org.left, org.top);
  957.                         EndContent(window);
  958.                         *retCtl = (*gcteViewFromTE)(te);
  959.                         return(Ctl2CNum(*retCtl));
  960.                     }
  961.                     list = (*gclFindActive)(window);
  962.                     if (list) {                                    /* If List control is active... */
  963.                         if ((*list)->rView.left < -8192)
  964.                             BeginFrame(window);
  965.                         else
  966.                             BeginContent(window);
  967.                         didKey = (*gclKey)(window, &evt);
  968.                         SetOrigin(org.left, org.top);
  969.                         EndContent(window);
  970.                         *retCtl = (*gclViewFromList)(list);
  971.                         ctlNum = Ctl2CNum(*retCtl);
  972.                         if (!didKey) ctlNum = 0;
  973.                         return(ctlNum);
  974.                     }
  975.                     break;
  976.             }
  977.         }
  978.     }
  979.  
  980.     return(0);
  981. }
  982.  
  983.  
  984.  
  985. /*****************************************************************************/
  986.  
  987.  
  988.  
  989. #pragma segment Controls
  990. static void    OpenActionWindow(OSType sftype)
  991. {
  992.     WindowPtr    window, fwindow;
  993.     FileRecHndl    frHndl;
  994.     long        attr, wkind;
  995.     OSErr        err;
  996.     
  997.     window = GetNextWindow(nil, sftype);
  998.     if (window) {
  999.         frHndl = (FileRecHndl)GetWRefCon(window);
  1000.         attr   = (*frHndl)->fileState.attributes;
  1001.         if (attr & kwHideOnClose) {
  1002.             if (!((WindowPeek)window)->visible)
  1003.                 ShowHide(window, true);
  1004.             wkind = (attr & (kwIsPalette | kwIsModalDialog));
  1005.             if (!(fwindow = FrontWindowOfType(wkind, false)))
  1006.                 fwindow = (WindowPtr)-1;
  1007.             CleanSendInFront(window, fwindow);
  1008.         }
  1009.         else window = nil;
  1010.     }
  1011.     if (!window) {
  1012.         DoSetResCursor(watchCursor);
  1013.         err = NewDocumentWindow(&frHndl, sftype, true);
  1014.         if (!err) {
  1015.             if (frHndl) {
  1016.                 window = (*frHndl)->fileState.window;
  1017.                 attr   = (*frHndl)->fileState.attributes;
  1018.                 if (!((WindowPeek)window)->visible)
  1019.                     ShowHide(window, true);
  1020.                 wkind = (attr & (kwIsPalette | kwIsModalDialog));
  1021.                 if (!(fwindow = FrontWindowOfType(wkind, false)))
  1022.                     fwindow = (WindowPtr)-1;
  1023.                 CleanSendInFront(window, fwindow);
  1024.             }
  1025.         }
  1026.         else {
  1027.             gDialogErr = err;
  1028.             NewDocumentWindow(nil, 'ERR#', false);
  1029.         }
  1030.     }
  1031. }
  1032.  
  1033.  
  1034.  
  1035. /*****************************************************************************/
  1036.  
  1037.  
  1038.  
  1039. #pragma segment Controls
  1040. static short    HandleScrollEvent(WindowPtr window, EventRecord *event)
  1041. {
  1042.     WindowPtr        oldPort;
  1043.     Point            clickLoc;
  1044.     short            part;
  1045.     ControlHandle    ctl;
  1046.     short            value, h, v;
  1047.  
  1048.     static ControlActionUPP    cupp;
  1049.  
  1050.     GetPort(&oldPort);
  1051.     SetPort(window);
  1052.     gScrollRct = window->portRect;
  1053.  
  1054.     gKeepOrg.h = gScrollRct.left;
  1055.     gKeepOrg.v = gScrollRct.top;
  1056.  
  1057.     SetOrigin(0, -16384);
  1058.     clickLoc = event->where;
  1059.     GlobalToLocal(&clickLoc);
  1060.         /* Scrollbars for window are offset -16384 vertically.  Get a local
  1061.         ** coordinate that corresponds to this negative space. */
  1062.  
  1063.     if (!(part = FindControl(clickLoc, window, &ctl))) {
  1064.         SetOrigin(gKeepOrg.h, gKeepOrg.v);            /* Restore the origin. */
  1065.         SetPort(oldPort);
  1066.         return(kScrollEvent);
  1067.     }
  1068.  
  1069.     gFrHndl = (FileRecHndl)GetWRefCon(window);
  1070.     if ((*gFrHndl)->fileState.vScroll)
  1071.         gScrollRct.right  -= 15;
  1072.     if ((*gFrHndl)->fileState.hScroll)
  1073.         gScrollRct.bottom -= 15;
  1074.  
  1075.     gScrollRct.left += (*gFrHndl)->fileState.leftSidebar;
  1076.     gScrollRct.top  += (*gFrHndl)->fileState.topSidebar;
  1077.  
  1078.     gVert = (((*ctl)->contrlRect.right - (*ctl)->contrlRect.left) == 16);
  1079.     switch (part) {
  1080.         case inThumb:
  1081.             value = GetControlValue(ctl);
  1082.             SetOrigin(0, -16384);
  1083.             part = TrackControl(ctl, clickLoc, nil);
  1084.             SetOrigin(gKeepOrg.h, gKeepOrg.v);            /* Restore the origin. */
  1085.             if (part) {
  1086.                 value -= GetControlValue(ctl);
  1087.                     /* Value now has CHANGE in position.  if position changed, scroll. */
  1088.                 if (value) {
  1089.                     h = v = 0;
  1090.                     if (gVert)
  1091.                         v = value;
  1092.                     else
  1093.                         h = value;
  1094.                     ScrollTheContent(window, h, v);
  1095.                 }
  1096.             }
  1097.             break;
  1098.         default:
  1099.             SetOrigin(0, -16384);
  1100.             if (!cupp) cupp = NewControlActionProc(ScrollActionProc);
  1101.             TrackControl(ctl, clickLoc, cupp);
  1102.             SetOrigin(gKeepOrg.h, gKeepOrg.v);            /* Restore the origin. */
  1103.             break;
  1104.     }
  1105.  
  1106.     AdjustScrollBars(window);
  1107.  
  1108.     SetPort(oldPort);
  1109.     return(kScrollEvent);
  1110. }
  1111.  
  1112.  
  1113.  
  1114. /*****************************************************************************/
  1115. /*****************************************************************************/
  1116.  
  1117.  
  1118.  
  1119. #pragma segment Controls
  1120. static pascal void    ScrollActionProc(ControlHandle scrollCtl, short part)
  1121. {
  1122.     WindowPtr    window;
  1123.     short        delta, value, h, v;
  1124.     short        oldValue, max;
  1125.     Point        org;
  1126.     RgnHandle    contPart, framePart;
  1127.  
  1128.     GetPort(&window);
  1129.  
  1130.     if (part) {                        /* If it was actually in the control. */
  1131.  
  1132.         switch (part) {
  1133.             case inUpButton:
  1134.             case inDownButton:        /* One line. */
  1135.                 delta = (gVert) ? (*gFrHndl)->fileState.vArrowVal : (*gFrHndl)->fileState.hArrowVal;
  1136.                 break;
  1137.             case inPageUp:            /* One page. */
  1138.             case inPageDown:
  1139.                 delta = (gVert) ? (*gFrHndl)->fileState.vPageVal : (*gFrHndl)->fileState.hPageVal;
  1140.                 break;
  1141.         }
  1142.  
  1143.         if ( (part == inUpButton) || (part == inPageUp) )
  1144.             delta = -delta;        /* Reverse direction for an upper. */
  1145.  
  1146.         value = (oldValue = GetControlValue(scrollCtl)) + delta;
  1147.         if (value < 0)
  1148.             value = 0;
  1149.         if (value > (max = GetControlMaximum(scrollCtl)))
  1150.             value = max;
  1151.  
  1152.         if (value != oldValue) {
  1153.  
  1154.             SetControlValue(scrollCtl, value);
  1155.             SetOrigin(gKeepOrg.h, gKeepOrg.v);
  1156.             h = oldValue - value;
  1157.             v = 0;
  1158.             if (gVert) {
  1159.                 v = h;
  1160.                 h = 0;
  1161.             }
  1162.  
  1163.             ScrollTheContent(window, h, v);
  1164.  
  1165.             DoUpdateSeparate(window, &contPart, &framePart);
  1166.             if (contPart) {
  1167.                 CopyRgn(contPart, ((WindowPeek)window)->updateRgn);
  1168.                 DisposeRgn(contPart);
  1169.                 ++gBeginUpdateNested;
  1170.                 BeginUpdate(window);
  1171.                 GetContentOrigin(window, &org);
  1172.                 SetOrigin(org.h, org.v);
  1173.                 DoImageDocument(gFrHndl);
  1174.                 EndUpdate(window);
  1175.                 --gBeginUpdateNested;
  1176.             }
  1177.             if (framePart) {
  1178.                 CopyRgn(framePart, ((WindowPeek)window)->updateRgn);
  1179.                 DisposeRgn(framePart);
  1180.             }
  1181.  
  1182.             SetOrigin(0, -16384);
  1183.         }
  1184.     }
  1185. }
  1186.  
  1187.  
  1188.  
  1189. /*****************************************************************************/
  1190.  
  1191.  
  1192.  
  1193. #pragma segment Controls
  1194. static void    ScrollTheContent(WindowPtr window, short h, short v)
  1195. {
  1196.     Point        org;
  1197.     RgnHandle    updateRgn;
  1198.  
  1199.     org.h = window->portRect.left;
  1200.     org.v = window->portRect.top;
  1201.     BeginContent(window);
  1202.     SetOrigin(org.h, org.v);
  1203.     ScrollRect(&gScrollRct, h, v, updateRgn = NewRgn());
  1204.     EndContent(window);
  1205.     InvalRgn(updateRgn);
  1206.     DisposeRgn(updateRgn);
  1207.     DoScrollFrame(window, h, v);
  1208. }
  1209.  
  1210.  
  1211.  
  1212. /*****************************************************************************/
  1213.  
  1214.  
  1215.  
  1216. #pragma segment Controls
  1217. static short    GetCtlPosition(ControlHandle ctl)
  1218. {
  1219.     ControlHandle    nextCtl;
  1220.     short            ctlNum;
  1221.  
  1222.     if (!ctl) return(0);
  1223.  
  1224.     nextCtl = ((WindowPeek)(*ctl)->contrlOwner)->controlList;
  1225.     for (ctlNum = 0;;) {
  1226.         if (!nextCtl) break;
  1227.         ++ctlNum;
  1228.         if (ctl == nextCtl) break;
  1229.         nextCtl = (*nextCtl)->nextControl;
  1230.     }
  1231.     return(ctlNum);
  1232. }
  1233.  
  1234.  
  1235.  
  1236. /*****************************************************************************/
  1237.  
  1238.  
  1239.  
  1240. /* Get the next Data control in the control list for a window. */
  1241.  
  1242. #pragma segment Controls
  1243. ControlHandle    CDataNext(WindowPtr window, ControlHandle ctl)
  1244. {
  1245.     ControlHandle    tempCtl;
  1246.     Rect            rct;
  1247.     static Handle    defProc;
  1248.  
  1249.     if (!window) return(nil);
  1250.  
  1251.     if (!defProc) {
  1252.         SetRect(&rct, 0, 0, 0, 0);
  1253.         tempCtl = NewControl(window, &rct, "\p", false, 0, 0, 0, gDataCtl, 0);
  1254.         if (tempCtl) {
  1255.             defProc = (*tempCtl)->contrlDefProc;
  1256.             DisposeControl(tempCtl);
  1257.         }
  1258.     }
  1259.  
  1260.     if (!ctl)
  1261.         ctl = ((WindowPeek)window)->controlList;
  1262.     else
  1263.         ctl = (*ctl)->nextControl;
  1264.  
  1265.     while (ctl) {
  1266.         if (StripAddress((*ctl)->contrlDefProc) == StripAddress(defProc)) return(ctl);
  1267.             /* The handle may be locked, which means that the hi-bit
  1268.             ** may be on, thus invalidating the compare.  Dereference the
  1269.             ** handles to get rid of this possibility. */
  1270.         ctl = (*ctl)->nextControl;
  1271.     }
  1272.  
  1273.     return(ctl);
  1274. }
  1275.  
  1276.  
  1277.  
  1278.