home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998…tember: Reference Library / Dev.CD Sep 98 RL1.toast / Technical Documentation / develop / develop Issue 23 / develop Issue 23 code / ProjectDrag 1.1b8.sea / ProjectDrag 1.1b8 / Sources / ProjectDrag Sources / PDDialogs.c / PDDialogs.c
Encoding:
C/C++ Source or Header  |  1995-08-01  |  16.5 KB  |  689 lines  |  [TEXT/MPS ]

  1. /* PDDialogs.c: Utility dialogs routines for ProjectDrag
  2.  *
  3.  * A set of applets for drag and drop source control by Tim Maroney.
  4.  * See develop, issue 23 for details.
  5.  *
  6.  * Built on DropShell by Leonard Rosenthol, Stephan Somogyi, and Marshall Clow,
  7.  * and using the MoreFiles utilities by Jim Luther.
  8.  *
  9.  * This software is free, but don't modify and redistribute it without
  10.  * changing the status window to indicate your name and your changes!
  11.  */
  12.  
  13. #include <Dialogs.h>
  14. #include <Errors.h>
  15. #include <Fonts.h>
  16. #include <Packages.h>
  17. #include <string.h>
  18.  
  19. #include "PDDialogs.h"
  20. #include "PDUtilities.h"
  21. #include "DSUtils.h"
  22. #include "TasksAndErrors.h"
  23.  
  24.  
  25. #define k3StateConfirmAlert 202
  26. #define k3ConfirmYesItem 1
  27. #define k3ConfirmCancelItem 2
  28. #define k3ConfirmNoItem 5
  29.  
  30. #define kUserSettingsDialog 203
  31. #define kUserNameItem 7
  32. #define kNicknameItem 8
  33.  
  34. #define    kTextDisplayDialog 205
  35. #define kMessageItem    2
  36. #define    kEditTextItem    4
  37. #define    kScrollerItem    5
  38.  
  39. #define k2StateConfirmAlert 206
  40. #define k2ConfirmYesItem 1
  41. #define k2ConfirmNoItem 2
  42.  
  43. #define    kMargin            4
  44. #define    kPageLines        16
  45. #define    kScrollToTop    0
  46. #define    kScrollToBottom    1
  47. #define    kCheckOneItem    5
  48. #define    kCheckTwoItem    6
  49.  
  50. static Boolean pUserSettingsInitialized = false;
  51. static Str63 pUserName;
  52. static Str15 pNickname;
  53.  
  54.  
  55. static TEHandle pTextHandle;
  56. static Boolean pPersistentFlag;
  57.  
  58.  
  59. pascal Boolean MyFilterProc(DialogPtr theDialog,EventRecord *ev,short *itemHit)
  60. {
  61.     return StdFilterProc(theDialog, ev, itemHit);
  62. }
  63.  
  64.  
  65. OSErr GetUserSettings(Str63 userName, Str15 userNickname, Boolean alwaysAsk)
  66. {
  67.     OSErr err = noErr;
  68.     FSSpec userSettingsFile;
  69.     
  70.     userName[0] = userNickname[0] = 0;
  71.     
  72.     if (!alwaysAsk && pUserSettingsInitialized)
  73.     {
  74.         /* just return the stashed copy */
  75.         BlockMove(pUserName, userName, pUserName[0] + 1);
  76.         BlockMove(pNickname, userNickname, pNickname[0] + 1);
  77.         return noErr;
  78.     }
  79.     
  80.     TaskStart(kProjectDragStrings, kGettingUserName, NULL, NULL, NULL, NULL);
  81.     
  82.     /* find the user settings file */
  83.     err = FindPreferencesFolder(&userSettingsFile.vRefNum, &userSettingsFile.parID);
  84.     if (err != noErr) return RaiseErrorNumber(err);
  85.     GetIndString(userSettingsFile.name, kProjectDragStrings, kPrefsFileName);
  86.  
  87.     {
  88.         /* try to get it from the preferences file */
  89.         short refNum;
  90.         long eof;
  91.         
  92.         err = FSpOpenDF(&userSettingsFile, fsRdPerm, &refNum);
  93.         if (err == noErr)
  94.         {
  95.             char buffer[72];
  96.             err = GetEOF(refNum, &eof);
  97.             if (err == noErr)
  98.             {
  99.                 if (eof > 72)
  100.                 {
  101.                     FSpDelete(&userSettingsFile);    /* bad prefs file */
  102.                     err = paramErr; /* aargh */
  103.                 }
  104.                 else
  105.                 {
  106.                     err = FSRead(refNum, &eof, buffer);
  107.                     if (err == noErr)
  108.                     {
  109.                         /* now parse it; CR-separated */
  110.                         StringPtr src = buffer;
  111.                         StringPtr dst = userName + 1;
  112.                         short len = 0;
  113.                         userName[0] = 0;
  114.                         while ((len < eof) && (len <= 63) && (*src != '\n'))
  115.                         {
  116.                             *dst++ = *src++;
  117.                             userName[0]++;
  118.                             len++;
  119.                         }
  120.                         eof -= (len + 1);
  121.                         userNickname[0] = 0;
  122.                         len = 0;
  123.                         src++;
  124.                         dst = userNickname + 1;
  125.                         while ((len < eof) && (len <= 7) && (*src != '\n'))
  126.                         {
  127.                             *dst++ = *src++;
  128.                             userNickname[0]++;
  129.                         }
  130.                         
  131.                         BlockMove(userName, pUserName, userName[0] + 1);
  132.                         BlockMove(userNickname, pNickname, userNickname[0] + 1);
  133.                         pUserSettingsInitialized = true;
  134.                     }
  135.                     FSClose(refNum);
  136.                     if (err != noErr)
  137.                         FSpDelete(&userSettingsFile);    /* bad prefs file */
  138.                     else if (!alwaysAsk)
  139.                     {
  140.                         TaskDone();
  141.                         return noErr;
  142.                     }
  143.                 }
  144.             }
  145.         }
  146.         err = noErr; /* ready to try the next approach */
  147.     }
  148.     
  149.     {
  150.         DialogPtr dialog;
  151.         Boolean done = false;
  152.         Rect r;
  153.         Handle h;
  154.         short type;
  155.         
  156.         dialog = GetNewDialog(kUserSettingsDialog, NULL, (WindowPtr)-1);
  157.         if (dialog == NULL) return RaiseErrorNumber(resNotFound);
  158.         SetDialogDefaultItem(dialog, ok);
  159.         SetDialogCancelItem(dialog, cancel);
  160.         SetDialogTracksCursor(dialog, true);
  161.         if (pUserSettingsInitialized)
  162.         {
  163.             GetDItem(dialog, kUserNameItem, &type, &h, &r);
  164.             SetIText(h, pUserName);
  165.             GetDItem(dialog, kNicknameItem, &type, &h, &r);
  166.             SetIText(h, pNickname);
  167.         }
  168.         SelectDialogItemText(dialog, kUserNameItem, 0, 32767);
  169.         while (!done)
  170.         {
  171.             short itemHit;
  172.             Str255 s;
  173.             Boolean enableOK = false;
  174.             ControlHandle ch;
  175.             
  176.             /* fix the OK button */
  177.             GetDItem(dialog, kUserNameItem, &type, &h, &r);
  178.             GetIText(h, s);
  179.             if (s[0] > 0)
  180.             {
  181.                 enableOK = true;
  182.             }
  183.             else
  184.             {
  185.                 GetDItem(dialog, kNicknameItem, &type, &h, &r);
  186.                 GetIText(h, s);
  187.                 if (s[0] > 0) enableOK = true;
  188.             }
  189.             GetDItem(dialog, ok, &type, &h, &r);
  190.             ch = (ControlHandle)h;
  191.             HiliteControl(ch, enableOK ? 0 : 255);
  192.             
  193.             ShowWindow(dialog);
  194.             ModalDialog(MyFilterProc, &itemHit);
  195.             switch (itemHit)
  196.             {
  197.             case ok:
  198.                 GetDItem(dialog, kUserNameItem, &type, &h, &r);
  199.                 GetIText(h, s);
  200.                 if (s[0] > 63) s[0] = 63;
  201.                 BlockMove(s, userName, s[0] + 1);
  202.                 
  203.                 GetDItem(dialog, kNicknameItem, &type, &h, &r);
  204.                 GetIText(h, s);
  205.                 if (s[0] > 7) s[0] = 7;
  206.                 BlockMove(s, userNickname, s[0] + 1);
  207.                 
  208.                 BlockMove(userName, pUserName, userName[0] + 1);
  209.                 BlockMove(userNickname, pNickname, userNickname[0] + 1);
  210.                 
  211.                 /* write the preferences file */
  212.                 err = FSpCreate(&userSettingsFile, 'ttxt', 'TEXT', smSystemScript);
  213.                 if (err == noErr || err == dupFNErr)
  214.                 {
  215.                     short refNum;
  216.                     err = FSpOpenDF(&userSettingsFile, fsWrPerm, &refNum);
  217.                     if (err == noErr)
  218.                     {
  219.                         char buffer[72];
  220.                         long count = userName[0] + userNickname[0] + 2;
  221.                         
  222.                         BlockMove(userName + 1, buffer, userName[0] + 1);
  223.                         buffer[userName[0]] = '\n';
  224.                         BlockMove(userNickname + 1, buffer + userName[0] + 1, userNickname[0] + 1);
  225.                         buffer[count - 1] = '\n';
  226.                         err = FSWrite(refNum, &count, buffer);
  227.                         FSClose(refNum);
  228.                         if (err != noErr)
  229.                             FSpDelete(&userSettingsFile);
  230.                     }
  231.                 }
  232.                 if (err != noErr)
  233.                 {
  234.                     /* alert the user that prefs couldn't be written; but continue! */
  235.                     ErrorAlert(kProjectDragStrings, kCantWritePrefs, err);
  236.                     err = noErr;
  237.                 }
  238.                 
  239.                 pUserSettingsInitialized = true;
  240.                 done = true;
  241.                 TaskDone();
  242.                 break;
  243.                 
  244.             case cancel:
  245.                 err = RaiseErrorNumber(userCanceledErr);
  246.                 done = true;
  247.                 break;
  248.             }
  249.         }
  250.         DisposeDialog(dialog);
  251.     }
  252.     
  253.     return err;
  254. }
  255.  
  256.  
  257. static pascal Boolean ConfirmAlertFilter(DialogPtr theDialog, EventRecord *theEvent,
  258.                                             short *itemHit)
  259. {
  260. #pragma unused (itemHit)
  261.  
  262.     SetDialogDefaultItem(theDialog, ok);
  263.     SetDialogCancelItem(theDialog, cancel);
  264.     
  265.     /* is it a mouse click in the persistent answer checkbox? */
  266.     if (theEvent->what == mouseDown)
  267.     {
  268.         GrafPtr save;
  269.         Point pt = theEvent->where;
  270.         short theItem;
  271.         
  272.         GetPort(&save);
  273.         SetPort(theDialog);
  274.         
  275.         GlobalToLocal(&pt);
  276.         theItem = FindDialogItem(theDialog, pt);
  277.         if (theItem >= 0)
  278.         {
  279.             Handle h;
  280.             Rect r;
  281.             short type;
  282.             
  283.             GetDialogItem(theDialog, ++theItem, &type, &h, &r);
  284.             if (type == ctrlItem + chkCtrl)
  285.             {
  286.                 ControlHandle ch = (ControlHandle)h;
  287.                 if (TrackControl(ch, pt, NULL) != 0)
  288.                 {
  289.                     Boolean value = !GetControlValue(ch);
  290.                     SetControlValue(ch, value);
  291.                     pPersistentFlag = value;
  292.                     theEvent->what = nullEvent; /* handled it */
  293.                     SetPort(save);
  294.                     return false;
  295.                 }
  296.             }
  297.             
  298.         }
  299.         SetPort(save);
  300.     }
  301.     
  302.     return StdFilterProc(theDialog, theEvent, itemHit);
  303. }
  304.  
  305.  
  306. ConfirmResponse ResTextYesNoCancel(short strListID, short strIndex,
  307.                                    StringPtr param1, StringPtr param2,
  308.                                    StringPtr param3, StringPtr param4)
  309. {
  310.     Str255 message;
  311.     ConfirmResponse answer;
  312.     
  313.     if (GetPersistentAnswer(strListID, strIndex, &answer))
  314.         return answer;
  315.     
  316.     ReplaceInIndString(message, strListID, strIndex, param1, param2, param3, param4);        
  317.     ParamText(message, NULL, NULL, NULL);
  318.     pPersistentFlag = false;
  319.     switch (Alert(k3StateConfirmAlert, ConfirmAlertFilter))
  320.     {
  321.     case k3ConfirmYesItem:
  322.         answer = kConfirmYes;
  323.         break;
  324.     case k3ConfirmCancelItem:
  325.         answer = kConfirmCancel;
  326.         break;
  327.     case k3ConfirmNoItem:
  328.     default:
  329.         answer = kConfirmNo;
  330.         break;
  331.     }
  332.     if (pPersistentFlag)
  333.         PersistentAnswer(strListID, strIndex, answer);
  334.     return answer;
  335. }
  336.  
  337.  
  338. Boolean ResTextYesNo(short strListID, short strIndex,
  339.                      StringPtr param1, StringPtr param2,
  340.                      StringPtr param3, StringPtr param4)
  341. {
  342.     Str255 message;
  343.     Boolean answer;
  344.     ConfirmResponse persistent;
  345.     
  346.     if (GetPersistentAnswer(strListID, strIndex, &persistent))
  347.         return (persistent == kConfirmYes);
  348.     
  349.     ReplaceInIndString(message, strListID, strIndex, param1, param2, param3, param4);        
  350.     ParamText(message, NULL, NULL, NULL);
  351.     pPersistentFlag = false;
  352.     switch (Alert(k2StateConfirmAlert, ConfirmAlertFilter))
  353.     {
  354.     case k2ConfirmYesItem:
  355.         answer = true;
  356.         break;
  357.     case k2ConfirmNoItem:
  358.     default:
  359.         answer = false;
  360.         break;
  361.     }
  362.     if (pPersistentFlag)
  363.         PersistentAnswer(strListID, strIndex, answer ? kConfirmYes : kConfirmNo);
  364.     return answer;
  365. }
  366.  
  367.  
  368. /*
  369.     Modal Dialog TextEdit useritem snippet
  370.     Steve Falkenburg -- MacDTS
  371.     
  372.     This snippet shows the steps necessary to implement a scrolling, editable text field
  373.     in a dialog.
  374.     
  375.     Modified to implement an output/diagnostic dialog for ProjectDrag by Tim Maroney;
  376. */
  377.  
  378.  
  379. // prototypes
  380.  
  381. void SetupTextDisplayDialog(DialogPtr theDialog, ConstStr255Param message, CStringHandle theText);
  382.  
  383. pascal void EditTextDrawProc(DialogPtr theDialog,short theItem);
  384. pascal Boolean MyDialogFilter(DialogPtr theDialog,EventRecord *ev,short *itemHit);
  385. Boolean HandleMouse(DialogPtr theDialog,Point pt,short modifiers);
  386.  
  387. void HandleScroller(DialogPtr theDialog,Point pt);
  388. pascal void ScrollBarAction(ControlHandle theControl,short part);
  389. void ScrollText(DialogPtr theDialog, short lines);
  390. void ReAlignTextToScrollbar(DialogPtr theDialog);
  391. void ReAlignScrollbarToText(DialogPtr theDialog);
  392.  
  393. ControlHandle GetScrollBar(DialogPtr theDialog);
  394.  
  395.  
  396.  
  397. /*    display dialog, and handle pretty standard ModalDialog loop.  The modal dialog loop doesn't
  398.     handle item hits to the scroll bar or text items.  These are handled through the filter
  399.     procedure
  400. */
  401.  
  402.  
  403. void ResTextDisplayDialog(short strListID, short index, CStringHandle theText)
  404. {
  405.     Str255 message;
  406.     GetIndString(message, strListID, index);
  407.     TextDisplayDialog(message, theText);
  408. }
  409.  
  410.  
  411. void TextDisplayDialog(ConstStr255Param message, CStringHandle theText)
  412. {
  413.     DialogPtr theDialog;
  414.     short item;
  415.     
  416.     theDialog = GetNewDialog(kTextDisplayDialog, NULL, (WindowPtr)-1L);
  417.     SetupTextDisplayDialog(theDialog, message, theText);
  418.  
  419.     ShowWindow(theDialog);
  420.     do {
  421.         ModalDialog(MyDialogFilter,&item);
  422.     } while (item != ok);
  423.     
  424.     TEDispose(pTextHandle);
  425.     DisposeDialog(theDialog);
  426. }
  427.  
  428.  
  429. /*    Creates the necessary data structures necessary to use the textedit item in our dialog.
  430. */
  431.  
  432. void SetupTextDisplayDialog(DialogPtr theDialog, ConstStr255Param message, CStringHandle theText)
  433. {
  434.     short iType;
  435.     Handle iHndl;
  436.     Rect iRect;
  437.     ControlHandle theControl;
  438.     Byte state;
  439.     
  440.     SetPort(theDialog);
  441.     
  442.     GetDItem(theDialog,kScrollerItem,&iType,&iHndl,&iRect);    // set up the scroll bar
  443.     theControl = (ControlHandle)iHndl;
  444.     SetCtlMin(theControl,0);                                        // (it's stored in a CNTL)
  445.     SetCtlMax(theControl,0);
  446.  
  447.     GetDItem(theDialog,kMessageItem,&iType,&iHndl,&iRect);
  448.     SetIText(iHndl, message);
  449.  
  450.     GetDItem(theDialog,kEditTextItem,&iType,&iHndl,&iRect);
  451.     SetDItem(theDialog,kEditTextItem,iType,(Handle)EditTextDrawProc,&iRect);
  452.     
  453.     InsetRect(&iRect,kMargin,kMargin);
  454.     
  455.     TextFont(applFont);
  456.     TextSize(9);
  457.     pTextHandle = TENew(&iRect,&iRect);            // create our textedit item
  458.     state = HGetState((Handle)theText);
  459.     HLock((Handle)theText);
  460.     TESetText(*theText, GetHandleSize((Handle)theText) - 1, pTextHandle);
  461.     HSetState((Handle)theText, state);
  462.     SetCtlMax(theControl, (*pTextHandle)->nLines);
  463.     TextFont(0);
  464.     TextSize(0);
  465.  
  466.     SetDialogDefaultItem(theDialog, ok);
  467.     SetDialogTracksCursor(theDialog, true);
  468. }
  469.  
  470.  
  471. /*    dialog user item draw procedure for text box.  It just calls FrameRect
  472. */
  473.  
  474. pascal void EditTextDrawProc(DialogPtr theDialog,short theItem)
  475. {
  476.     short iType;
  477.     Handle iHndl;
  478.     Rect iRect;
  479.     GrafPtr savePort;
  480.     
  481.     GetPort(&savePort);
  482.     SetPort(theDialog);
  483.     
  484.     GetDItem(theDialog,theItem,&iType,&iHndl,&iRect);
  485.     FrameRect(&iRect);
  486.     
  487.     TEUpdate(&iRect, pTextHandle);
  488.     
  489.     SetPort(savePort);
  490. }
  491.  
  492.  
  493. /*    this is the main dispatcher for events to be passed off to the scroll bar or textedit box.
  494.     looks sort of like a WaitNextEvent event handler.
  495. */
  496.  
  497. pascal Boolean MyDialogFilter(DialogPtr theDialog,EventRecord *ev,short *itemHit)
  498. {
  499.     Boolean handledIt = StdFilterProc(theDialog, ev, itemHit);
  500.     if (handledIt)
  501.         return true;
  502.  
  503.     switch (ev->what) {
  504.         case mouseDown:
  505.             return HandleMouse(theDialog,ev->where,ev->modifiers);
  506.         default:
  507.             return false;
  508.     }
  509. }
  510.  
  511.  
  512. /*    mouse-down hander.  here, we see if the mousedown was in the scrollbar or in the textedit
  513.     record.  if in the textedit item, we call teclick.  If in the scrollbar, we call handlescroller
  514.     to do further processing
  515. */
  516.  
  517. Boolean HandleMouse(DialogPtr theDialog,Point pt,short modifiers)
  518. {
  519.     short iType;
  520.     Handle iHndl;
  521.     Rect textRect,scrollerRect;
  522.     GrafPtr savePort;
  523.     Boolean shiftDown,result;
  524.     
  525.     GetPort(&savePort);
  526.     SetPort(theDialog);
  527.     
  528.     shiftDown = modifiers & shiftKey;
  529.     GlobalToLocal(&pt);
  530.     
  531.     GetDItem(theDialog,kEditTextItem,&iType,&iHndl,&textRect);
  532.     GetDItem(theDialog,kScrollerItem,&iType,&iHndl,&scrollerRect);
  533.     
  534.     if (PtInRect(pt,&scrollerRect)) {
  535.         HandleScroller(theDialog,pt);
  536.         result = true;
  537.     }
  538.     else
  539.     {
  540.         result = false;
  541.     }
  542.         
  543.     SetPort(savePort);
  544.     
  545.     return result;
  546. }
  547.  
  548.  
  549. /*    here, we see which part of the scrollbar was clicked in by calling findcontrol.  trackcontrol
  550.     is then called with the appropriate action proc if in one of the buttons or page areas.  if
  551.     in the thumb, the text is simply re-aligned to the new scrollbar position
  552. */
  553.  
  554. void HandleScroller(DialogPtr theDialog,Point pt)
  555. {
  556.     short part;
  557.     ControlHandle theControl;
  558.     
  559.     part = FindControl(pt,theDialog,&theControl);
  560.     switch (part) {
  561.         case inUpButton:
  562.         case inDownButton:
  563.         case inPageUp:
  564.         case inPageDown:
  565.             TrackControl(theControl,pt,ScrollBarAction);
  566.             break;
  567.         case inThumb:
  568.             TrackControl(theControl,pt,nil);
  569.             ReAlignTextToScrollbar(theDialog);
  570.             break;
  571.     }
  572. }
  573.  
  574.  
  575. /*    trackcontrol callback used to determine which direction to scroll the text, and by how much.
  576.     once this is known, the text is scrolled, and the scrollbar adjusted.
  577. */
  578.  
  579. pascal void ScrollBarAction(ControlHandle theControl,short part)
  580. {
  581.     DialogPtr theDialog;
  582.     short lines;
  583.     short ctlValue,ctlMax,ctlMin;
  584.     
  585.     ctlMax = GetCtlMax(theControl);
  586.     ctlMin = GetCtlMin(theControl);
  587.     ctlValue = GetCtlValue(theControl);
  588.     
  589.     theDialog = (*theControl)->contrlOwner;
  590.     
  591.     switch (part) {
  592.         case inUpButton:
  593.             lines = -1;
  594.             break;
  595.         case inDownButton:
  596.             lines = 1;
  597.             break;
  598.         case inPageUp:
  599.             lines = -kPageLines;
  600.             break;
  601.         case inPageDown:
  602.             lines = kPageLines;
  603.             break;
  604.         default:
  605.             return;
  606.     }
  607.  
  608.     if ((ctlValue+lines)>ctlMax)
  609.         lines = ctlMax-ctlValue;
  610.     if ((ctlValue+lines)<ctlMin)
  611.         lines = ctlMin-ctlValue;
  612.         
  613.     if (lines!=0) {
  614.         ScrollText(theDialog, lines);
  615.         SetCtlValue(theControl,ctlValue+lines);
  616.     }
  617. }
  618.  
  619.  
  620. /*    sets the text top line to be the same as the current scrollbar position.  this is called after
  621.     a thumb movement in the scrollbar.
  622. */
  623.  
  624. void ReAlignTextToScrollbar(DialogPtr theDialog)
  625. {
  626.     ControlHandle scrollBar;
  627.     short controlScrollPosition,textScrollPosition,scrollDelta,scrollPix;
  628.     
  629.     scrollBar = GetScrollBar(theDialog);
  630.     
  631.     controlScrollPosition = GetCtlValue(scrollBar);
  632.     textScrollPosition = ((**pTextHandle).viewRect.top - (**pTextHandle).destRect.top) / (**pTextHandle).lineHeight;
  633.     scrollDelta = textScrollPosition - controlScrollPosition;
  634.     scrollPix = scrollDelta * (*pTextHandle)->lineHeight;
  635.     TEScroll(0,scrollPix,pTextHandle);
  636. }
  637.  
  638.  
  639. /*    sets the scrollbar thumb to the current text position.  this is called after autoscrolling,
  640.     which may occur after a call to TEKey, or during a drag-scroll
  641. */
  642.  
  643. void ReAlignScrollbarToText(DialogPtr theDialog)
  644. {
  645.     ControlHandle scrollBar;
  646.     short textScrollPosition;
  647.         
  648.     scrollBar = GetScrollBar(theDialog);
  649.     
  650.     textScrollPosition = ((**pTextHandle).viewRect.top - (**pTextHandle).destRect.top) / (**pTextHandle).lineHeight;
  651.     SetCtlValue(scrollBar,textScrollPosition);
  652. }
  653.  
  654.  
  655. /*    scrolls the text by the delta passed in to the function.  called in response to clicking the
  656.     arrows or page areas of the scrollbar to move the text
  657. */
  658.  
  659. void ScrollText(DialogPtr theDialog, short lines)
  660. {
  661.     short scrollPix;
  662.     short textScrollPosition;
  663.     short theMax = GetCtlMax(GetScrollBar(theDialog));
  664.     
  665.     textScrollPosition = ((**pTextHandle).viewRect.top - (**pTextHandle).destRect.top) / (**pTextHandle).lineHeight;
  666.     if ((textScrollPosition+lines)<0)
  667.         lines = -textScrollPosition;
  668.     if ((textScrollPosition+lines)>theMax)
  669.         lines = theMax-textScrollPosition;
  670.                 
  671.     scrollPix = lines * (*pTextHandle)->lineHeight;
  672.     
  673.     TEScroll(0,-scrollPix,pTextHandle);
  674. }
  675.  
  676.  
  677. /*    utility procedure to return a handle to the scrollbar control
  678. */
  679.  
  680. ControlHandle GetScrollBar(DialogPtr theDialog)
  681. {
  682.     Handle theScroller;
  683.     short iType;
  684.     Rect iRect;
  685.     
  686.     GetDItem(theDialog,kScrollerItem,&iType,&theScroller,&iRect);
  687.     return (ControlHandle)theScroller;
  688. }
  689.