home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / clintsrc.sit / DAtextedit.c < prev    next >
Text File  |  1990-06-19  |  14KB  |  578 lines

  1. /*========================================================================
  2. ===  DAtextedit.c
  3. ===
  4. ===  Greg Anderson
  5. ===  29 Kerr Hall
  6. ===  Social Sciences Computing
  7. ===  University of California at Santa Cruz
  8. ===  Santa Cruz CA  95062
  9. ===
  10. ===  (408) 459-2658
  11. ===  sirkm@ssyx.ucsc.edu
  12. ===
  13. ===  Textedit routines.
  14. ===
  15. ========================================================================*/
  16. #include    <types.h>
  17. #include    <osutils.h>
  18. #include    <memory.h>
  19. #include    <devices.h>
  20. #include    <events.h>
  21. #include    <quickdraw.h>
  22. #include    <fonts.h>
  23. #include    <windows.h>
  24. #include    <files.h>
  25. #include    <errors.h>
  26. #include    <toolutils.h>
  27. #include    <packages.h>
  28.  
  29. #include    <Limits.h>
  30. #include    <Controls.h>
  31. #include    <TextEdit.h>
  32. #include    <Dialogs.h>
  33. #include    <Desk.h>
  34. #include    <Scrap.h>
  35. #include    <Traps.h>
  36. #include    <Lists.h>
  37. #include    <Menus.h>
  38.  
  39.  
  40. #include    "unixDA.h"
  41. #include    "DA.h"
  42.  
  43. /*----------------------------------------------------------------------
  44. |  Make a new TextEdit record
  45. ----------------------------------------------------------------------*/
  46. TEHandle makeTE( Rect destRect, Rect viewRect )
  47. {
  48.     TEHandle        te;
  49.     TextStyle        tStyle;
  50.     
  51.     te = TEStylNew(&destRect, &viewRect);
  52.     if( te == nil ) return(te);
  53.     /*
  54.      *  Set the textedit style to small plain monaco
  55.      */
  56.     tStyle.tsFont = monaco;
  57.     tStyle.tsFace = 0;
  58.     tStyle.tsSize = teSize;
  59.     TESetStyle(doFont|doFace|doSize,&tStyle,false,te);
  60.  
  61.     adjustViewRect(te);
  62.     TEAutoView(true, te);
  63.  
  64.     return( te );
  65. }
  66.  
  67. /*----------------------------------------------------------------------
  68. |  Respond to a non-COMMAND keypress.
  69. ----------------------------------------------------------------------*/
  70. void doKeyDown( EventRecord *event, DCtlPtr dCtl)
  71. {
  72.     long        newCrs = 0;
  73.     char        key,
  74.                 code,
  75.                 msg[8];
  76.     int            selLen = ((*DA_te)->selEnd - (*DA_te)->selStart);
  77.  
  78.     key  = (event->message & charCodeMask);
  79.     code = (event->message &  keyCodeMask) >> 8;
  80.     /*
  81.      *  Control-C is special.
  82.      */
  83.     if( key == 3 )
  84.     {
  85.         doAbort(dCtl);
  86.         return;
  87.     }
  88.     switch( code )
  89.     {
  90.     case 122:    doUndo(dCtl);
  91.                 return;
  92.     case 120:    doCut(dCtl);
  93.                 return;
  94.     case 99:    doCopy(dCtl);
  95.                 return;
  96.     case 118:    doPaste(dCtl);
  97.                 return;
  98.     case 116:    /* pg up */
  99.                 pageTE( dCtl, ((*DA_te)->viewRect.bottom - (*DA_te)->viewRect.top) );
  100.                 return;
  101.     case 121:    /* pg dn */
  102.                 pageTE( dCtl,-((*DA_te)->viewRect.bottom - (*DA_te)->viewRect.top) );
  103.                 return;
  104.     case 119:    /* end */
  105.                 newCrs = 40000L;
  106.     case 115:    /* home */
  107.                 TESetSelect(newCrs,newCrs, DA_te );
  108.                 adjustScrollbars(DA_window, false);
  109.                 adjustTE(DA_window);
  110.                 return;
  111.     }
  112.     /*
  113.      *  If there is a connection, then keys are sent to the
  114.      *  server instead of the window.  Translate RETURN to LF,
  115.      *  because that's what the unix SuperServer likes to see.
  116.      */
  117.     if( connectionState( dCtl ) >= 8 )
  118.     {
  119.         if( key == '\n') key = '\r';
  120.         
  121.         msg[0] = key;
  122.         msg[1] = 0;
  123.         SendTCP( dCtl, msg );
  124.     }
  125.     /*
  126.      *  Did the user type DELETE?
  127.      */
  128.     else if( key == kDelChar )
  129.     {
  130.         /*
  131.          *  If there is no selection, we make DELETE act like a
  132.          *  backspace by making a small one-character selection 
  133.          *  (to the left) and then deleting it
  134.          */
  135.         if( !selLen )
  136.         {
  137.             if( (*DA_te)->selStart )
  138.                 --((*DA_te)->selStart);
  139.         }
  140.         setUndoCut( dCtl );
  141.         TEDelete( DA_te );
  142.         adjustScrollbars(DA_window, false);
  143.         adjustTE(DA_window);
  144.     }
  145.     /*
  146.      *  A non-delete-type character was entered:  do we have room for it?
  147.      */
  148.     else if( ((*DA_te)->teLength - selLen + 1) < kMaxTELength )
  149.     {
  150.         if( (DA_global->undoType == undoNothing) || (selLen > 0) )
  151.             setUndoCut( dCtl );
  152.         ++(DA_global->undoTo);
  153.         TEKey(key, DA_te);
  154.         adjustScrollbars(DA_window, false);
  155.         adjustTE(DA_window);
  156.     }
  157.     else
  158.         alertUser(dCtl, eExceedChar);
  159. }
  160.  
  161. /*----------------------------------------------------------------------
  162. |  Process a COMMAND-key.
  163. ----------------------------------------------------------------------*/
  164. void doCommandKey( EventRecord *event, DCtlPtr dCtl)
  165. {
  166.     char        key;
  167.  
  168.     key = event->message & charCodeMask;
  169.     switch( key )
  170.     {
  171.     case 'z':    doUndo(dCtl);
  172.                 break;
  173.     case 'x':    doCut(dCtl);
  174.                 break;
  175.     case 'c':    doCopy(dCtl);
  176.                 break;
  177.     case 'v':    doPaste(dCtl);
  178.                 break;
  179.     case '.':    doAbort(dCtl);
  180.                 break;
  181.     case 'a':    TESetSelect(0,kMaxTELength,DA_te);
  182.                 break;
  183.     case 'r':    doReconnect(dCtl);
  184.                 break;
  185.     }
  186. }
  187.  
  188. /*----------------------------------------------------------------------
  189. |  Hilite the 'Edit' menu.  (Pretty funky technique, but it works.)
  190. ----------------------------------------------------------------------*/
  191. HiliteEditMenu( )
  192. {
  193.     HiliteMenu( (short)(( MenuKey('c') >> 16 ) & 0xFF) );
  194. }
  195.  
  196. /*----------------------------------------------------------------------
  197. |  Scroll the TE record one page
  198. ----------------------------------------------------------------------*/
  199. void pageTE( DCtlPtr dCtl, int amount)
  200. {    
  201.     TEScroll(0, amount , DA_te );
  202.     adjustScrollbars(DA_window, false);
  203.     adjustTE(DA_window);
  204. }
  205.  
  206. /*----------------------------------------------------------------------
  207. |  Cut or copy the selected region of text.
  208. ----------------------------------------------------------------------*/
  209. void doCutCopy( DCtlPtr dCtl, int CutOrCopy )
  210. {
  211.     long        total, contig;
  212.  
  213.     /*
  214.      *  If the selection start == the selection end, then there
  215.      *  is no selection.  Exit if this is the case.
  216.      */
  217.     if( (*DA_te)->selEnd == (*DA_te)->selStart ) return;
  218.     HiliteEditMenu();
  219.     /*
  220.      *  Zero the scrap, as we are about to replace it.
  221.      */
  222.     if ( ZeroScrap() == noErr )
  223.     {
  224.         PurgeSpace(&total, &contig);
  225.         if ((*DA_te)->selEnd - (*DA_te)->selStart + kTESlop > contig)
  226.             alertUser(dCtl, eNoSpaceCut);
  227.         else
  228.         {
  229.             /*
  230.              *  Cut or copy the text and export the TextEdit scrap to the
  231.              *  system scrap.
  232.              */
  233.             if( CutOrCopy )
  234.             {
  235.                 setUndoCut( dCtl );
  236.                 TECut(DA_te);
  237.             }
  238.             else
  239.                 TECopy(DA_te);
  240.             if ( TEToScrap() != noErr )
  241.             {
  242.                 alertUser(dCtl, eNoCut);
  243.                 ZeroScrap();
  244.             }
  245.         }
  246.     }
  247.     adjustScrollbars(DA_window, false);
  248.     adjustTE(DA_window);
  249.     shortPause();
  250.     HiliteMenu(0);
  251. }
  252.  
  253. /*----------------------------------------------------------------------
  254. |  Cut the selected region of text.
  255. ----------------------------------------------------------------------*/
  256. void doCut( DCtlPtr dCtl )
  257. {
  258.     doCutCopy(dCtl, 1);
  259. }
  260.  
  261. /*----------------------------------------------------------------------
  262. |  Copy the selected region of text.
  263. ----------------------------------------------------------------------*/
  264. void doCopy( DCtlPtr dCtl )
  265. {
  266.     doCutCopy(dCtl, 0);
  267. }
  268.  
  269. /*----------------------------------------------------------------------
  270. |  Check if the handle of a textedit record has enough
  271. |  room for the text about to be pasted into it.
  272. ----------------------------------------------------------------------*/
  273. int roomToPaste( TEHandle te )
  274. {
  275.     Handle        aHandle;
  276.     long        newSize,
  277.                 oldSize;
  278.     int            saveErr;
  279.     
  280.     aHandle = (Handle) TEGetText( te );
  281.     oldSize = GetHandleSize(aHandle);
  282.     newSize = oldSize + TEGetScrapLen() + kTESlop;
  283.     SetHandleSize(aHandle, newSize);
  284.     saveErr = MemError();
  285.     SetHandleSize(aHandle, oldSize);
  286.     return(saveErr);
  287. }
  288.  
  289. /*----------------------------------------------------------------------
  290. |  Paste the system scrap into the TextEdit window.
  291. ----------------------------------------------------------------------*/
  292. void doPaste( DCtlPtr dCtl )
  293. {
  294.     Handle        aHandle;
  295.     char        *scan;
  296.     long        newSize,
  297.                 oldSize;
  298.     int            saveErr;
  299.     
  300.     HiliteEditMenu();
  301.     /*
  302.      *  If there is an established connection, paste goes to
  303.      *  server instead of window.
  304.      */
  305.     if( connectionState( dCtl ) >= 8 )
  306.     {
  307.         aHandle = NewHandle(1L);
  308.         MoveHHi(aHandle);
  309.         HLock(aHandle);
  310.         GetScrap(aHandle,'TEXT',&oldSize);
  311.         HLock(aHandle);
  312.         scan = *aHandle;
  313.         while( *scan )
  314.             *scan++ = ( *scan == '\n' ? '\r' : *scan );
  315.         SendTCP( dCtl, *aHandle );
  316.         DisposHandle(aHandle);
  317.     }
  318.     /*
  319.      *  Import the system scrap to the TextEdit scrap.
  320.      */
  321.     else if ( TEFromScrap() == noErr )
  322.     {
  323.         if ( TEGetScrapLen() + ((*DA_te)->teLength -
  324.             ((*DA_te)->selEnd - (*DA_te)->selStart)) > kMaxTELength )
  325.             alertUser(dCtl, eExceedPaste);
  326.         else
  327.         {
  328.             setUndoPaste(dCtl);
  329.             TEFromScrap();
  330.             if( roomToPaste( DA_te ) != noErr )
  331.                 alertUser(dCtl, eNoSpacePaste);
  332.             else
  333.                 TEPaste(DA_te);
  334.         }
  335.     }
  336.     else
  337.         alertUser(dCtl, eNoPaste);
  338.     
  339.     adjustScrollbars(DA_window, false);
  340.     adjustTE(DA_window);
  341.     shortPause();
  342.     HiliteMenu(0);
  343. }
  344.  
  345. /*----------------------------------------------------------------------
  346. |  Clear the current selection.
  347. ----------------------------------------------------------------------*/
  348. void doClear( DCtlPtr dCtl )
  349. {
  350.     setUndoCut( dCtl );
  351.     HiliteEditMenu();
  352.     TECut(DA_te);
  353.     adjustScrollbars(DA_window, false);
  354.     adjustTE(DA_window);
  355.     shortPause();
  356.     HiliteMenu(0);
  357. }
  358.  
  359. /*----------------------------------------------------------------------
  360. |  Set up a style for addTEstring
  361. ----------------------------------------------------------------------*/
  362. void setStyle( ScrpSTElement *thisSty,long start,int face )
  363. {
  364.     thisSty->scrpStartChar     = start;
  365.     thisSty->scrpHeight         = teLineHeight;
  366.     thisSty->scrpAscent         = teAscent;
  367.     thisSty->scrpFont         = monaco;
  368.     thisSty->scrpFace         = face;
  369.     thisSty->scrpSize         = teSize;
  370.     thisSty->scrpColor.red     = 0;
  371.     thisSty->scrpColor.green = 0;
  372.     thisSty->scrpColor.blue     = ( face == 0 ? 0 : 30000 );
  373. }
  374.  
  375. /*----------------------------------------------------------------------
  376. |  Decide what style the current character should use based on what
  377. |  character preceeded the backspace.
  378. |
  379. |  [underscore] [BS] [character] == underlined text
  380. |  [character]  [BS] [character] == bold text
  381. ----------------------------------------------------------------------*/
  382. Style decideStyle( char lastC, char nextC )
  383. {
  384.     if( lastC == nextC )
  385.         return( bold );
  386.     if( (lastC == '_') || (nextC == '_') )
  387.         return( underline );
  388.  
  389.     return(0);
  390. }
  391.  
  392. /*----------------------------------------------------------------------
  393. |  Add a string to the END of the TextEdit window.
  394. |
  395. |  This code scans through the input string looking for backspaces;
  396. |  if found, they are removed & the style of the preceeding character
  397. |  may be modified.
  398. ----------------------------------------------------------------------*/
  399. void addTEstring( DCtlPtr dCtl, char *string )
  400. {
  401.     StScrpHandle    addStyle;
  402.     ScrpSTElement    *thisSty;
  403.     CharsHandle        textHandle;
  404.     Handle            tmpHandle;
  405.     Style            curSty        = 0,
  406.                     nextSty;
  407.     short            *runPtr,
  408.                     *startRec,
  409.                     styleRuns    = 0,
  410.                     maxRuns        = 10;
  411.     Size            styLen,
  412.                     tmpLen;
  413.     long            len = 0,
  414.                     teLen,
  415.                     atChar;
  416.     char            lastC,
  417.                     *walk,
  418.                     *follow;
  419.     int                saveStart    = (*DA_te)->selStart,
  420.                     saveEnd        = (*DA_te)->selEnd;
  421.     
  422.     len = fix_cr(string);
  423.     while( (*string) && (*string == 8) )
  424.     {
  425.         --len;
  426.         ++string;
  427.         textHandle = TEGetText( DA_te );
  428.         teLen = (*DA_te)->teLength;
  429.         if( teLen )
  430.         {
  431.             lastC = (char)( (*textHandle)[teLen-1] );
  432.             TEKey(8, DA_te);
  433.             curSty = decideStyle( lastC, *string );
  434.             if( *string == '_' )
  435.                 *string = lastC;
  436.         }
  437.     }
  438.     if( !len ) return;
  439.     
  440.     /*
  441.      *  Set up style information
  442.      */
  443.     styLen = (Size)sizeof(short) + maxRuns * (Size)sizeof(ScrpSTElement);
  444.     addStyle = (StScrpHandle)NewHandle( styLen );
  445.     if( !addStyle )
  446.     {
  447.         alertUser( dCtl, eNoMemory );
  448.         return;
  449.     }
  450.     runPtr = (short *)*addStyle;
  451.     
  452.     startRec = runPtr + 1;
  453.     thisSty = (ScrpSTElement *)(startRec);
  454.     styleRuns = 1;
  455.     setStyle( thisSty,0L,curSty );
  456.     /*
  457.      *  Walk through the string looking for backspaces
  458.      */
  459.     follow = string;
  460.     walk = string + 1;
  461.     atChar = 0;
  462.     while( *walk )
  463.     {
  464.         lastC = *follow;
  465.         ++atChar;
  466.         if( *walk == 8 )
  467.         {
  468.             ++walk;
  469.             len -= 2;
  470.             --atChar;
  471.             if( !(*walk) )
  472.             {
  473.                 --follow;
  474.                 break;
  475.             }
  476.             nextSty = decideStyle( lastC, *walk );
  477.             if( atChar == 0 )
  478.             {
  479.                 thisSty->scrpFace = nextSty;
  480.                 curSty = nextSty;
  481.             }
  482.             if( *walk == '_' )
  483.                 *walk = lastC;
  484.         }
  485.         else
  486.         {
  487.             ++follow;
  488.             if( *(walk+1) != 8 )
  489.                 nextSty = 0;
  490.         }
  491.  
  492.         if( nextSty != curSty )
  493.         {
  494.             if( styleRuns >= maxRuns )
  495.             {
  496.                 tmpLen = styLen;
  497.                 tmpHandle = NewHandle( tmpLen );
  498.                 BlockMove( (Ptr)*addStyle, (Ptr)*tmpHandle, tmpLen );
  499.                 maxRuns += 10;
  500.                 styLen = (Size)sizeof(short) + maxRuns * (Size)sizeof(ScrpSTElement);
  501.                 ReallocHandle( (Handle)addStyle, styLen );
  502.                 BlockMove( (Ptr)*tmpHandle, (Ptr)*addStyle, tmpLen );
  503.                 DisposHandle( tmpHandle );
  504.                 
  505.                 runPtr = (short *)*addStyle;
  506.                 startRec = runPtr + 1;
  507.                 thisSty = (ScrpSTElement *)(startRec) + (styleRuns-1);
  508.             }
  509.             ++styleRuns;
  510.             thisSty += 1;
  511.             curSty = nextSty;
  512.             setStyle( thisSty,atChar,curSty );
  513.         }
  514.         
  515.         *follow = *walk++;
  516.     }
  517.     *runPtr = styleRuns;
  518.     /*
  519.     *(++follow) = 0;
  520.     */
  521.     
  522.     if( (*DA_te)->teLength + len < kMaxTELength )
  523.     {
  524.         TEDeactivate(DA_te);
  525.         TESetSelect(kMaxTELength,kMaxTELength,DA_te);
  526.         TEStylInsert(string,len,addStyle,DA_te);
  527.         /* TEInsert(string,len,DA_te); */
  528.         TESetSelect(kMaxTELength,kMaxTELength,DA_te);
  529.         /* TESetSelect(saveStart,saveEnd,DA_te); */
  530.         TEActivate(DA_te);
  531.         adjustScrollbars(DA_window, false);
  532.         adjustTE(DA_window);
  533.         
  534.         DisposHandle( (Handle)addStyle );
  535.     }
  536.     else
  537.     {
  538.         DisposHandle( (Handle)addStyle );
  539.         alertUser(dCtl, eExceedChar);
  540.         doAbort( dCtl );        
  541.     }
  542. }
  543.  
  544. /*----------------------------------------------------------------------
  545. |  Update the TERec's view rect so that it is the greatest multiple of
  546. |  the lineHeight that still fits in the old viewRect.
  547. ----------------------------------------------------------------------*/
  548. void adjustViewRect(docTE)
  549.     TEHandle    docTE;
  550. {
  551.     TEPtr        te;
  552.     
  553.     te = *docTE;
  554.     te->viewRect.bottom = (((te->viewRect.bottom - te->viewRect.top) / teLineHeight)
  555.                             * teLineHeight) + te->viewRect.top;
  556. }
  557.  
  558. /*----------------------------------------------------------------------
  559. |  Scroll the TERec around to match up to the potentially updated
  560. |  scrollbar values. This is really useful when the window has been
  561. |  resized such that the scrollbars became inactive but the TERec was
  562. |  already scrolled.
  563. ----------------------------------------------------------------------*/
  564. void adjustTE(window)
  565.     WindowPtr    window;
  566. {
  567.     TEPtr        te;
  568.     
  569.     te = *((DocumentPeek)window)->docTE;
  570.     
  571.     TEScroll((te->viewRect.left - te->destRect.left) -
  572.             GetCtlValue(((DocumentPeek)window)->docHScroll),
  573.             (te->viewRect.top - te->destRect.top) -
  574.                 (GetCtlValue(((DocumentPeek)window)->docVScroll) *
  575.                 teLineHeight),
  576.             ((DocumentPeek)window)->docTE);
  577. }
  578.