home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / WASTE 1.1 / WEHighLevelEditing.c < prev    next >
Encoding:
Text File  |  1994-11-02  |  29.8 KB  |  1,000 lines  |  [TEXT/MPCC]

  1. on;
  2.     while ((*hLast)->hNext != nil)
  3.         hLast = (*hLast)->hNext;
  4.  
  5.     // { prepend hAction in front of the action stack }
  6.     pWE = *((*hAction)->hOwner);
  7.     (*hLast)->hNext = (WEActionHandle)pWE->hActionStack;
  8.     pWE->hActionStack = (Handle)hAction;
  9.  
  10.     return noErr;
  11. } // { WEPushAction }
  12.  
  13. pascal OSErr WENewAction(long rangeStart, long rangeEnd, long newTextLength,
  14.                             WEActionKind actionKind, WEActionFlags actionFlags,
  15.                             WEHandle hWE, WEActionHandle *hAction)
  16. {
  17.     WEActionPtr pAction;
  18.     OSErr err;
  19.  
  20.     // { allocate a new action record }
  21.     err = _WEAllocate(sizeof(WEAction), kAllocClear, (Handle *)hAction);
  22.     if (err != noErr) 
  23.         goto cleanup1;
  24.  
  25.     // { lock it down }
  26.     HLock((Handle)hAction);
  27.     pAction = **hAction;
  28.  
  29.     // { fill in the fields }
  30.     pAction->hOwner = hWE;
  31.     pAction->delRangeStart = rangeStart;
  32.     pAction->delRangeLength = newTextLength;
  33.     pAction->insRangeLength = rangeEnd - rangeStart;
  34.     pAction->actionKind = actionKind;
  35.     pAction->actionFlags = actionFlags;
  36.  
  37.     // { remember selection range }
  38.     WEGetSelection(&pAction->hiliteStart, &pAction->hiliteEnd, hWE);
  39.  
  40.     // { allocate a handle to hold the text to be saved, unless otherwise specified }
  41.     if ((actionFlags & weAFDontSaveText) == 0) 
  42.     {
  43.         err = _WEAllocate(0, kAllocTemp, &pAction->hText);
  44.         if (err != noErr) 
  45.             goto cleanup1;
  46.     }
  47.  
  48.     // { allocate a handle to hold the styles to be saved, unless otherwise specified }
  49.     if ((actionFlags & weAFDontSaveStyles) == 0) 
  50.     {
  51.         err = _WEAllocate(0, kAllocTemp, &pAction->hStyles);
  52.         if (err != noErr) 
  53.             goto cleanup1;
  54.     }
  55.  
  56.     // { allocate a handle to hold the "soup" to be saved, unless otherwise specified }
  57.     if ((actionFlags & weAFDontSaveSoup) == 0) 
  58.     {
  59.         err = _WEAllocate(0, kAllocTemp, &pAction->hSoup);
  60.         if (err != noErr) 
  61.             goto cleanup1;
  62.     }
  63.     
  64.     // { make a copy of text range }
  65.     err = WECopyRange(rangeStart, rangeEnd, pAction->hText, (Handle)pAction->hStyles,
  66.                     pAction->hSoup, hWE);
  67.     if (err != noErr)
  68.         goto cleanup1;
  69.  
  70.     // { unlock action record }
  71.     HUnlock((Handle)hAction);
  72.  
  73.     // { skip clean-up section }
  74.     goto cleanup0;
  75.  
  76. cleanup1:
  77.     // { clean up }
  78.     _WEForgetHandle(&pAction->hText);
  79.     _WEForgetHandle(&pAction->hStyles);
  80.     _WEForgetHandle(&pAction->hSoup);
  81.     _WEForgetHandle((Handle *)hAction);
  82.  
  83. cleanup0:
  84.     // { return result code }
  85.     return err;
  86.  
  87. } // { WENewAction }
  88.  
  89. pascal void WEDisposeAction(WEActionHandle hAction)
  90. {
  91.     WEActionPtr pAction;
  92.     WEActionHandle hNext;
  93.  
  94.     while (hAction != nil)
  95.     {
  96.         // { lock the action record }
  97.         HLock((Handle)hAction);
  98.         pAction = *hAction;
  99.         hNext = pAction->hNext;
  100.  
  101.         // { throw away text, styles and soup }
  102.         _WEForgetHandle(&pAction->hText);
  103.         _WEForgetHandle(&pAction->hStyles);
  104.         _WEForgetHandle(&pAction->hSoup);
  105.  
  106.         // { throw away the action record itself }
  107.         DisposeHandle((Handle)hAction);
  108.  
  109.         // { repeat the same sequence with all linked actions }
  110.         hAction = hNext;
  111.  
  112.     } // { while }
  113. } // { WEDisposeAction }
  114.  
  115. pascal void WEForgetAction(WEActionHandle *hAction)
  116. {
  117.     WEActionHandle theAction;
  118.  
  119.     theAction = *hAction;
  120.     if (theAction != nil) 
  121.     {
  122.         *hAction = nil;
  123.         WEDisposeAction(theAction);
  124.     }
  125. } // { WEForgetAction }
  126.  
  127. pascal OSErr WEDoAction(WEActionHandle hAction)
  128. {
  129.     WEActionHandle hRedoAction;
  130.     WEActionPtr pAction;
  131.     WEHandle hWE;
  132.     WEPtr pWE;
  133.     long offset, delOffset, insOffset;
  134.     long redrawStart, redrawEnd;
  135.     Boolean saveActionLock, saveWELock, saveTextLock;
  136.     OSErr err;
  137.  
  138.     // { sanity check: make sure hAction isn't NIL }
  139.     if (hAction == nil) 
  140.     {
  141.         return nilHandleErr;
  142.     }
  143.     
  144.     // { get handle to associated WE instance }
  145.     hWE = (*hAction)->hOwner;
  146.  
  147.     // { lock the WE record }
  148.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  149.     pWE = *hWE;
  150.  
  151.     // { hide selection highlighting and the caret }
  152.     _WEHiliteRange(pWE->selStart, pWE->selEnd, hWE);
  153.     if (BTST(pWE->flags, weFCaretVisible))
  154.         _WEBlinkCaret(hWE);
  155.  
  156.     redrawStart = LONG_MAX;
  157.     redrawEnd = 0;
  158.  
  159.     do
  160.     {
  161.  
  162.         // { lock the action record }
  163.         saveActionLock = _WESetHandleLock((Handle)hAction, true);
  164.         pAction = *hAction;
  165.         offset = pAction->delRangeStart;
  166.         delOffset = offset + pAction->delRangeLength;
  167.         insOffset = offset + pAction->insRangeLength;
  168.  
  169.         // { if undo support is enabled, save the range to be affected by this action }
  170.         if (BTST(pWE->flags, weFUndoSupport)) 
  171.         {
  172.             if (WENewAction(offset, delOffset, pAction->insRangeLength, pAction->actionKind,
  173.                 (pAction->actionFlags ^ weAFIsRedo), hWE, &hRedoAction) == noErr) 
  174.             {
  175.                 if (WEPushAction(hRedoAction) != noErr)
  176.                 {
  177.                     ;
  178.                 }
  179.             }
  180.         }
  181.         if (pAction->hText != nil) 
  182.         {
  183.  
  184.             // { delete the range to replace }
  185.             err = _WEDeleteRange(offset, delOffset, hWE);
  186.             if (err != noErr) 
  187.                 goto cleanup;
  188.  
  189.             // { insert the saved text }
  190.             saveTextLock = _WESetHandleLock(pAction->hText, true);
  191.             err = _WEInsertText(offset, *pAction->hText, pAction->insRangeLength, hWE);
  192.             _WESetHandleLock(pAction->hText, saveTextLock);
  193.             if (err != noErr) 
  194.                 goto cleanup;
  195.         }
  196.  
  197.         // { apply the saved styles, if any }
  198.         if (pAction->hStyles != nil) 
  199.         {
  200.             err = _WEApplyStyleScrap(offset, insOffset, (StScrpHandle)pAction->hStyles, hWE);
  201.             if (err != noErr) 
  202.                 goto cleanup;
  203.         }
  204.  
  205.         // { the same goes for the soup }
  206.         if (pAction->hSoup != nil) 
  207.         {
  208.             err = _WEApplySoup(offset, pAction->hSoup, hWE);
  209.             if (err != noErr) 
  210.                 goto cleanup;
  211.         }
  212.  
  213.         // { adjust redraw range }
  214.         if (offset < redrawStart) 
  215.             redrawStart = offset;
  216.         if (insOffset > redrawEnd) 
  217.             redrawEnd = insOffset;
  218.  
  219.         // { unlock action record }
  220.         _WESetHandleLock((Handle)hAction, saveActionLock);
  221.  
  222.         // { go to next action }
  223.         hAction = (*hAction)->hNext;
  224.     } while (hAction != nil);
  225.  
  226.     // { restore the original selection range }
  227.     pWE->selStart = pAction->hiliteStart;
  228.     pWE->selEnd = pAction->hiliteEnd;
  229.  
  230.     // { redraw the text }
  231.     err = _WERedraw(redrawStart, redrawEnd, hWE);
  232.     if (err != noErr) 
  233.         goto cleanup;
  234.  
  235.     // { clear result code }
  236.     err = noErr;
  237.  
  238. cleanup:
  239.     // { unlock the WE record }
  240.     _WESetHandleLock((Handle)hWE, saveWELock);
  241.  
  242.     // { return result code }
  243.     return err;
  244. } // { WEDoAction }
  245.  
  246. pascal OSErr WEUndo(WEHandle hWE)
  247. {
  248.     WEActionHandle hAction;
  249.     OSErr retval;
  250.  
  251.     // { stop any ongoing inline input session }
  252.     WEStopInlineSession(hWE);
  253.  
  254.     // { "detach" the action stack from the WE instance }
  255.     hAction = (WEActionHandle)(*hWE)->hActionStack;
  256.     (*hWE)->hActionStack = nil;
  257.  
  258.     // { return an error code if no actions are associated with the specified WE instance }
  259.     if (hAction == nil)
  260.         return weCantUndoErr;
  261.  
  262.     // { perform the action... }
  263.     retval = WEDoAction(hAction);
  264.  
  265.     // { ...and throw it away }
  266.     WEDisposeAction(hAction);
  267.  
  268.     return retval;
  269. }
  270.  
  271. pascal void WEClearUndo(WEHandle hWE)
  272. {
  273.  
  274.     // { dispose of the action chain associated with the given WE instance }
  275.     WEForgetAction((WEActionHandle *)&(*hWE)->hActionStack);
  276. } // { WEClearUndo }
  277.  
  278. pascal WEActionKind WEGetUndoInfo(Boolean *redoFlag, WEHandle hWE)
  279. {
  280.     WEActionKind retval;
  281.     
  282.     retval = weAKNone;        // { assume no actions have been saved }
  283.     *redoFlag = false;
  284.  
  285.     if ((*hWE)->hActionStack != nil) 
  286.     {
  287.         retval = (*((WEActionHandle)(*hWE)->hActionStack))->actionKind;
  288.         *redoFlag = (((*((WEActionHandle)(*hWE)->hActionStack))->actionFlags & weAFIsRedo) != 0);
  289.     }
  290.     return retval;
  291. } // { WEGetUndoInfo }
  292.  
  293. pascal void _WEAdjustUndoRange(long moreBytes, WEHandle hWE)
  294. {
  295.     WEActionHandle hAction;
  296.  
  297.     hAction = (WEActionHandle)(*hWE)->hActionStack;
  298.     if (hAction != nil) 
  299.         (*hAction)->delRangeLength = (*hAction)->delRangeLength + moreBytes;
  300.  
  301. } // { _WEAdjustUndoRange }
  302.  
  303. pascal OSErr _WETypeChar(char theByte, WEHandle hWE)
  304. {
  305.     WEPtr pWE;
  306.     DoubleByte db;
  307.     long offset, endOffset, charLength;
  308.     short byteType;
  309.     short saveFont;
  310.     GrafPtr savePort;
  311.     OSErr err;
  312.  
  313.     pWE = *hWE;                    // { the WE record must be already locked }
  314.     charLength = 1;                // { assume 1-byte character by default }
  315.     db.firstByte = theByte;
  316.     offset = pWE->selStart;
  317.  
  318.     // { delete current selection, if any }
  319.     err = _WEDeleteRange(offset, pWE->selEnd, hWE);
  320.     if (err != noErr) 
  321.         goto cleanup2;
  322.     
  323.     // (*pWE->selEnd = offset;*)
  324.  
  325.     // { make sure the font script is synchronized with the keyboard script }
  326.     _WESynchNullStyle(hWE);
  327.  
  328.     if (BTST(pWE->flags, weFDoubleByte))
  329.     {
  330.  
  331.         // { special processing for double-byte characters }
  332.         if (pWE->firstByte != 0) 
  333.         {
  334.  
  335.             // { if this byte is the second half of a double-byte character, }
  336.             // { insert the two bytes at the same time (flush the double-byte cache) }
  337.             db.firstByte = pWE->firstByte;
  338.             db.secondByte = theByte;
  339.             charLength = 2;
  340.             pWE->firstByte = 0;
  341.         }
  342.         else
  343.         {
  344.  
  345.             // { determine the byte-type of theByte; first set up the port and its font }
  346.             GetPort(&savePort);
  347.             SetPort(pWE->port);
  348.             saveFont = pWE->port->txFont;
  349.             TextFont(pWE->nullStyle.runStyle.tsFont);
  350.  
  351.             // { call CharByte }
  352.             byteType = CharByte(&theByte, 0);
  353.  
  354.             // { put back font and port }
  355.             TextFont(saveFont);
  356.             SetPort(savePort);
  357.  
  358.             // { if theByte is the first half of a double-byte character, just cache it and exit }
  359.             if (byteType == smFirstByte) 
  360.             {
  361.                 pWE->firstByte = theByte;
  362.                 goto cleanup1;
  363.             }
  364.         }
  365.  
  366.     } // { if double-byte script installed }
  367.  
  368.     // { insert the new character into the text }
  369.     err = _WEInsertText(offset, (Ptr)&db, charLength, hWE);
  370.     if (err != noErr) 
  371.         goto cleanup2;
  372.  
  373.     // { adjust undo buffer for the new character }
  374.     _WEAdjustUndoRange(charLength, hWE);
  375.  
  376.     // { invalid the null style }
  377.     BCLR(pWE->flags, weFUseNullStyle);
  378.  
  379.     // { move the insertion point after the new character }
  380.     endOffset = offset + charLength;
  381.     pWE->selStart = endOffset;
  382.     pWE->selEnd = endOffset;
  383.  
  384.     // { redraw the text }
  385.     err = _WERedraw(offset, endOffset, hWE);
  386.     if (err != noErr) 
  387.         goto cleanup2;
  388.  
  389. cleanup1:
  390.     // { clear result code }
  391.     err = noErr;
  392.  
  393. cleanup2:
  394.     // { return result code }
  395.     return err;
  396.  
  397. } // { _WETypeChar }
  398.  
  399. pascal OSErr _WEPrependStyle(Handle hStyleScrap, WERunInfo *info, long offsetDelta)
  400. {
  401.     // { compare the stylistic attributes in info with the first element of the specified }
  402.     // { style scrap: if they differ, prepend a new element to the style scrap. }
  403.     // { in any case, advance all character offsets in the style scrap by offsetDelta }
  404.  
  405.     TEStyleScrapPtr pScrap;
  406.     Size scrapSize;
  407.     short i;
  408.     OSErr err;
  409.  
  410.     pScrap = *(TEStyleScrapHandle)hStyleScrap;
  411.  
  412.     // { compare this style info with that stored in the first element of our private style scrap }
  413.     if (_WEBlockCmp((Ptr)&pScrap->scrpStyleTab[0].scrpTEAttrs, (Ptr)&info->runAttrs,
  414.          sizeof(TERunAttributes))
  415.          == false) 
  416.     {
  417.  
  418.         // { leng the style scrap }
  419.         scrapSize = GetHandleSize(hStyleScrap);
  420.         SetHandleSize(hStyleScrap, scrapSize + sizeof(TEStyleScrapElement));
  421.         err = MemError();
  422.         if (err != noErr) 
  423.             return err;
  424.  
  425.         // { move old contents forward }
  426.         pScrap = *(TEStyleScrapHandle)hStyleScrap;
  427.         BlockMoveData(&pScrap->scrpStyleTab[0], &pScrap->scrpStyleTab[1], scrapSize - sizeof(short));
  428.  
  429.         // { insert a new element at the beginning }
  430.         pScrap->scrpStyleTab[0].scrpStartChar = 0;
  431.         pScrap->scrpStyleTab[0].scrpTEAttrs = *(TERunAttributes *)&info->runAttrs;
  432.  
  433.         // { increment scrap counter }
  434.         pScrap->scrpNStyles = pScrap->scrpNStyles + 1;
  435.  
  436.     } // { if not _WEBlockCmp }
  437.  
  438.     // { update char offsets within the style scrap }
  439.     for(i = pScrap->scrpNStyles - 1; i>0; i--)
  440.     {
  441.         pScrap->scrpStyleTab[i].scrpStartChar = pScrap->scrpStyleTab[i].scrpStartChar + offsetDelta;
  442.     }
  443.  
  444.     // { return result code }
  445.     return noErr;
  446. } // { _WEPrependStyle }
  447.  
  448. pascal OSErr _WEPrependObject(Handle hSoup, WERunInfo *info, long offsetDelta)
  449. {
  450.     // { if info describes an embedded object, prepend a new object descriptor, }
  451.     // { complete with the associated object data, to the specified soup. }
  452.     // { in any case, advance all character offsets in the soup by offsetDelta }
  453.  
  454.     WEObjectDescPtr pDesc;
  455.     WESoupPtr pSoup;
  456.     Size soupSize, objectDataSize, extraSize;
  457.     OSErr err;
  458.  
  459.     // { get size of existing soup }
  460.     soupSize = GetHandleSize(hSoup);
  461.  
  462.     // { extract object descriptor handle from WERunInfo record }
  463.     // { if hObject is non-NIL, info describes an embedded object }
  464.     if (info->runAttrs.runStyle.tsObject != nil) 
  465.     {
  466.         pDesc = *(WEObjectDescHandle)(info->runAttrs.runStyle.tsObject);
  467.  
  468.         // { get size of object data }
  469.         objectDataSize = GetHandleSize(pDesc->objectDataHandle);
  470.  
  471.         // { extra size to add to existing soup is descriptor size + object data size }
  472.         extraSize = sizeof(WESoup) + objectDataSize;
  473.  
  474.         // { resize the soup }
  475.         SetHandleSize(hSoup, soupSize + extraSize);
  476.         err = MemError();
  477.         if (err != noErr)
  478.             return err;
  479.  
  480.         // { move old contents forward }
  481.         pSoup = *(WESoupHandle)hSoup;
  482.         BlockMoveData((Ptr)pSoup, (Ptr)pSoup + extraSize, soupSize);
  483.  
  484.         // { insert the new object descriptor at the beginning }
  485.         _WEBlockClr((Ptr)pSoup, sizeof(WESoup));
  486.         pDesc = *(WEObjectDescHandle)(info->runAttrs.runStyle.tsObject);
  487.         pSoup->soupType = pDesc->objectType;
  488.         pSoup->soupSize = pDesc->objectSize;
  489.         pSoup->soupDataSize = objectDataSize;
  490.  
  491.         // {  copy the object data }
  492.         BlockMoveData(*pDesc->objectDataHandle, (Ptr)pSoup + sizeof(WESoup), objectDataSize);
  493.     }
  494.     else
  495.     {
  496.         pSoup = *(WESoupHandle)hSoup;
  497.         extraSize = 0;
  498.     }
  499.  
  500.     // { update char offsets within the soup }
  501.     while (soupSize > 0)
  502.     {
  503.         pSoup = (WESoupPtr)((Ptr)pSoup + extraSize);
  504.         pSoup->soupOffset = pSoup->soupOffset + offsetDelta;
  505.         extraSize = pSoup->soupDataSize + sizeof(WESoup);
  506.         soupSize = soupSize - extraSize;
  507.     }
  508.  
  509.     return noErr;
  510. } // { _WEPrependObject }
  511.  
  512. pascal OSErr _WEBackspace(WEHandle hWE)
  513. {
  514.     // { this routine is called by WEKey to handle the backspace key }
  515.     // { the WE record is guaranteed to be already locked }
  516.  
  517.     WEPtr pWE;
  518.     WEActionPtr pAction;
  519.     long rangeStart, rangeEnd, charLength;
  520.     char *pChars;
  521.     WERunInfo runInfo;
  522.     Boolean saveActionLock;
  523.     OSErr err;
  524.  
  525.     pWE = *hWE;
  526.  
  527.     // { calculate the text range to delete }
  528.     // { if the selection is non-empty, delete that }
  529.     rangeStart = pWE->selStart;
  530.     rangeEnd = pWE->selEnd;
  531.     if (rangeStart == rangeEnd) 
  532.     {
  533.  
  534.         // { otherwise the selection is an insertion point }
  535.         // { do nothing if insertion point is at the beginning of the text }
  536.         if (rangeStart == 0) return noErr; 
  537.  
  538.         // { determine the byte-type of the character preceding the insertion point }
  539.         if (WECharByte(rangeStart - 1, hWE) == smSingleByte) 
  540.             charLength = 1;
  541.         else
  542.             charLength = 2;
  543.         rangeStart = rangeStart - charLength;
  544.  
  545.         if (pWE->hActionStack != nil) 
  546.         {
  547.             // { UNDO SUPPORT FOR BACKSPACES }
  548.  
  549.             // { lock the action record }
  550.             saveActionLock = _WESetHandleLock(pWE->hActionStack, true);
  551.             pAction = *(WEActionHandle)pWE->hActionStack;
  552.  
  553.             // { backspaces over the newly entered text aren't a problem }
  554.             if (pAction->delRangeLength > 0) 
  555.                 pAction->delRangeLength = pAction->delRangeLength - charLength;
  556.             else
  557.             {
  558.  
  559.                 // { the hard part comes when backspacing past the new text because }
  560.                 // { the user is about to delete a character not included in the block we saved }
  561.  
  562.                 // { leng our saved text handle }
  563.                 SetHandleSize(pAction->hText, pAction->insRangeLength + charLength);
  564.                 err = MemError();
  565.                 if (err != noErr) return err;
  566.  
  567.                 // { move old contents forward }
  568.                 pChars = *(char **)pAction->hText;
  569.                 BlockMoveData(pChars, &pChars[charLength], pAction->insRangeLength);
  570.  
  571.                 // { prepend the character to be deleted to the beginning of our saved text handle }
  572.                 pChars[0] = WEGetChar(rangeStart, hWE);
  573.                 if (charLength == 2) 
  574.                     pChars[1] = WEGetChar(rangeStart + 1, hWE);
  575.  
  576.                 // { adjust internal counters }
  577.                 pAction->insRangeLength = pAction->insRangeLength + charLength;
  578.                 pAction->delRangeStart = pAction->delRangeStart - charLength;
  579.  
  580.                 // { get style run info associated with the about-to-be-deleted character }
  581.                 WEGetRunInfo(rangeStart, &runInfo, hWE);
  582.  
  583.                 // { prepend a new style element to our style scrap, if necessary }
  584.                 err = _WEPrependStyle(pAction->hStyles, &runInfo, charLength);
  585.                 if (err != noErr) return err; 
  586.  
  587.                 // { do the same with our object "soup" }
  588.                 err = _WEPrependObject(pAction->hSoup, &runInfo, charLength);
  589.                 if (err != noErr) return err;
  590.             
  591.             } // { if deleting old text }
  592.  
  593.             // { unlock the action record }
  594.             _WESetHandleLock(pWE->hActionStack, saveActionLock);
  595.  
  596.         } // { if undo support is enabled }
  597.     } // { if selection is empty }
  598.  
  599.     err = _WEDeleteRange(rangeStart, rangeEnd, hWE);
  600.     if (err != noErr) return err;
  601.  
  602.     // { keep track of current selection range }
  603.     pWE->selStart = rangeStart;
  604.     pWE->selEnd = rangeStart;
  605.  
  606.     // { redraw the text }
  607.     err = _WERedraw(rangeStart, rangeStart, hWE);
  608.     
  609.     return err;
  610. } // { _WEBackspace }
  611.  
  612. pascal Boolean _WEIsTyping(WEHandle hWE)
  613. {
  614.     WEPtr pt, hWE);
  615.     if (err != noErr) 
  616.         goto cleanup;
  617.  
  618.     // { clear result code }
  619.     err = noErr;
  620.  
  621. cleanup:
  622.     // { unlock the WE record }
  623.     _WESetHandleLock((Handle)hWE, saveWELock);
  624.  
  625.     // { return result code }
  626.     return err;
  627. } // { WEInsert }
  628.  
  629. pascal OSErr WEInsertObject(OSType objectType, Handle objectDataHandle, Point objectSize, WEHandle hWE)
  630. {
  631.     WEPtr pWE;
  632.     WEActionHandle hAction;
  633.     long offset, endOffset;
  634.     WETextStyle ts;
  635.     char marker;
  636.     Boolean saveWELock;
  637.     OSErr err;
  638.  
  639.     _WEBlockClr((Ptr)&ts, sizeof(ts));
  640.  
  641.     // { stop any ongoing inline input session }
  642.     WEStopInlineSession(hWE);
  643.  
  644.     // { lock the WE record }
  645.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  646.     pWE = *hWE;
  647.     offset = pWE->selStart;
  648.  
  649.     // { call the 'new' handler to initialize private object storage (if any) }
  650.     // { and to calculate the default size for this object }
  651.     err = _WENewObject(objectType, objectDataHandle, hWE, (WEObjectDescHandle *)&ts.tsObject);
  652.     if (err != noErr) 
  653.         goto cleanup;
  654.  
  655.     // { use the specified object size, unless it is (0, 0), in which case keep the default size }
  656.     if (*((long *)&objectSize) != 0) 
  657.         (*(WEObjectDescHandle)ts.tsObject)->objectSize = objectSize;
  658.  
  659.     // { if undo support is enabled, save current selection range }
  660.     if (BTST(pWE->flags, weFUndoSupport)) 
  661.     {
  662.         WEClearUndo(hWE);
  663.         if (WENewAction(offset, pWE->selEnd, 1, weAKUnspecified, 0, hWE, &hAction) == noErr) 
  664.             if (WEPushAction(hAction) != noErr) 
  665.                 { ; }
  666.     }
  667.  
  668.     // { delete current selection }
  669.     err = _WEDeleteRange(offset, pWE->selEnd, hWE);
  670.     if (err != noErr) 
  671.         goto cleanup;
  672.  
  673.     // { insert a kObjectMarker character at the insertion point }
  674.     marker = kObjectMarker;
  675.     err = _WEInsertText(offset, &marker, 1, hWE);
  676.     if (err != noErr) 
  677.         goto cleanup;
  678.  
  679.     // { move the insertion point after the inserted text }
  680.     endOffset = offset + 1;
  681.     pWE->selStart = endOffset;
  682.     pWE->selEnd = endOffset;
  683.  
  684.     // { record a reference to the object descriptor in the style table }
  685.     err = _WESetStyleRange(offset, endOffset, weDoObject, &ts, hWE);
  686.     ts.tsObject = nil;
  687.     if (err != noErr) 
  688.         goto cleanup;
  689.  
  690.     // { invalid the null style }
  691.     BCLR(pWE->flags, weFUseNullStyle);
  692.  
  693.     // { redraw the text }
  694.     err = _WERedraw(offset, endOffset, hWE);
  695.     if (err != noErr) 
  696.         goto cleanup;
  697.  
  698.     // { clear result code }
  699.     err = noErr;
  700.  
  701. cleanup:
  702.     // { clean up }
  703.     _WEForgetHandle(&ts.tsObject);
  704.  
  705.     // { unlock the WE record }
  706.     _WESetHandleLock((Handle)hWE, saveWELock);
  707.  
  708.     // { return result code }
  709.     return err;
  710. } // { WEInsertObject }
  711.  
  712. pascal OSErr WEDelete(WEHandle hWE)
  713. {
  714.     WEPtr pWE;
  715.     WEActionHandle hAction;
  716.     long rangeStart, rangeEnd;
  717.     Boolean saveWELock;
  718.     OSErr err;
  719.  
  720.     // { stop any ongoing inline input session }
  721.     WEStopInlineSession(hWE);
  722.  
  723.     // { lock the WE record }
  724.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  725.     pWE = *hWE;
  726.  
  727.     // { get current selection range }
  728.     rangeStart = pWE->selStart;
  729.     rangeEnd = pWE->selEnd;
  730.  
  731.     // { do nothing if the selection range is empty }
  732.     if (rangeStart < rangeEnd) 
  733.     {
  734.  
  735.         // { range extension for intelligent cut-and-paste }
  736.         _WEIntelligentCut(&rangeStart, &rangeEnd, hWE);
  737.  
  738.         // { if undo support is enabled, save the range to be deleted }
  739.         if (BTST(pWE->flags, weFUndoSupport)) 
  740.         {
  741.             WEClearUndo(hWE);
  742.             if (WENewAction(rangeStart, rangeEnd, 0, weAKClear, 0, hWE, &hAction) == noErr) 
  743.                 if (WEPushAction(hAction) != noErr) 
  744.                     { ; }
  745.         }
  746.  
  747.         // { delete the selection range }
  748.         err = _WEDeleteRange(rangeStart, rangeEnd, hWE);
  749.         if (err != noErr) 
  750.             goto cleanup;
  751.  
  752.         // { reset the selection range }
  753.         pWE->selStart = rangeStart;
  754.         pWE->selEnd = rangeStart;
  755.  
  756.         // { redraw the text }
  757.         err = _WERedraw(rangeStart, rangeStart, hWE);
  758.         if (err != noErr) 
  759.             goto cleanup;
  760.  
  761.     } // { if non-empty selection }
  762.  
  763.     // { clear result code }
  764.     err = noErr;
  765.  
  766. cleanup:
  767.     // { unlock the WE record }
  768.     _WESetHandleLock((Handle)hWE, saveWELock);
  769.  
  770.     // { return result code }
  771.     return err;
  772. } // { WEDelete }
  773.  
  774. pascal OSErr WECut(WEHandle hWE)
  775. {
  776.     OSErr err;
  777.  
  778.     // { Cut is just Copy + Delete }
  779.     err = WECopy(hWE);
  780.     if (err != noErr) return err;
  781.  
  782.     err = WEDelete(hWE);
  783.     if (err != noErr) return err;
  784.  
  785.     // { change the action kind of the most recent action, if any }
  786.     if ((*hWE)->hActionStack != nil) 
  787.         (*(WEActionHandle)(*hWE)->hActionStack)->actionKind = weAKCut;
  788.  
  789.     return noErr;
  790. }  // { WECut }
  791.  
  792. pascal Boolean WECanPaste(void)
  793. {
  794.     long scrapOffset;
  795.     OSType objectType;
  796.     short index;
  797.  
  798.     // { return TRUE if the desk scrap contains a text flavor }
  799.     if (GetScrap(nil, kTypeText, &scrapOffset) > 0) return true;
  800.  
  801.     // { see if the desk scrap contains a flavor matching one of the registered object types }
  802.     index = 0;
  803.     while (_WEGetIndObjectType(index, &objectType) == noErr)
  804.     {
  805.         if (GetScrap(nil, objectType, &scrapOffset) > 0) return true;
  806.         index = index + 1;
  807.     } // { while }
  808.  
  809.     return false;
  810. } // { WECanPaste }
  811.  
  812. pascal OSErr WEPaste(WEHandle hWE)
  813. {
  814.     Handle hItem;
  815.     Handle hStyles;
  816.     Handle hSoup;
  817.     long selStart;
  818.     long scrapOffset;
  819.     OSType objectType;
  820.     Point objectSize;
  821.     short index;
  822.     OSErr err;
  823.     Point zeroPoint = {0, 0};
  824.  
  825.     hItem = nil;
  826.     hStyles = nil;
  827.     hSoup = nil;
  828.     selStart = (*hWE)->selStart;
  829.  
  830.     // { allocate a handle to hold a scrap item }
  831.     err = _WEAllocate(0, kAllocTemp, &hItem);
  832.     if (err != noErr) 
  833.         goto cleanup;
  834.  
  835.     // { look for a text flavor }
  836.     if (GetScrap(hItem, kTypeText, &scrapOffset) <= 0) 
  837.     {
  838.  
  839.         // { no text: look for a flavor matching one of the registered object types }
  840.         index = 0;
  841.         while (_WEGetIndObjectType(index, &objectType) == noErr)
  842.         {
  843.             if (GetScrap(hItem, objectType, &scrapOffset) > 0) 
  844.             {
  845.             
  846.                 // { found a registered type: create a new object out of the tagged data }
  847.                 err = WEInsertObject(objectType, hItem, zeroPoint, hWE);
  848.  
  849.                 // { if successful, set hItem to NIL so clean-up section won't kill the object data }
  850.                 if (err == noErr) 
  851.                     hItem = nil;
  852.                 goto cleanup;
  853.             }
  854.  
  855.             // { try with next flavor }
  856.             index = index + 1;
  857.         } // { while }
  858.  
  859.         // { nothing pasteable: return an error code }
  860.         err = noTypeErr;
  861.         goto cleanup;
  862.     }
  863.  
  864.     // { allocate a handle to hold the style scrap, if any }
  865.     err = _WEAllocate(0, kAllocTemp, &hStyles);
  866.     if (err != noErr) 
  867.         goto cleanup;
  868.  
  869.     // { look for a 'styl' item accompanying the text }
  870.     if (GetScrap(hStyles, kTypeStyles, &scrapOffset) <= 0) 
  871.         // { forget the handle if nothing was found or an error occurred }
  872.         _WEForgetHandle(&hStyles);
  873.  
  874.     // { allocate a handle to hold the soup, if any }
  875.     err = _WEAllocate(0, kAllocTemp, &hSoup);
  876.     if (err != noErr) 
  877.         goto cleanup;
  878.  
  879.     // { look for a 'SOUP' item accompanying the text }
  880.     if (GetScrap(hSoup, kTypeSoup, &scrapOffset) <= 0) 
  881.         // { forget the handle if nothing was found or an error occurred }
  882.         _WEForgetHandle(&hSoup);
  883.  
  884.     // { lock down the text }
  885.     HLock(hItem);
  886.  
  887.     // { insert the text }
  888.     err = WEInsert(*hItem, GetHandleSize(hItem), (StScrpHandle)hStyles, hSoup, hWE);
  889.  
  890. cleanup:
  891.     // { if successful, change the action kind of the most recent action, if any }
  892.     if (err == noErr) 
  893.         if ((*hWE)->hActionStack != nil) 
  894.             (*(WEActionHandle)(*hWE)->hActionStack)->actionKind = weAKPaste;
  895.  
  896.     // { clean up }
  897.     _WEForgetHandle(&hItem);
  898.     _WEForgetHandle(&hStyles);
  899.     _WEForgetHandle(&hSoup);
  900.  
  901.     // { return result code }
  902.     return err;
  903. } // { WEPaste }
  904.  
  905. pascal OSErr WESetStyle(short mode, TextStyle *ts, WEHandle hWE)
  906. {
  907.     WEPtr pWE;
  908.     WEActionHandle hAction;
  909.     ScriptCode fontScript;
  910.     Boolean saveWELock;
  911.     OSErr err;
  912.  
  913.     // { stop any ongoing inline input session }
  914.     WEStopInlineSession(hWE);
  915.  
  916.     // { lock the WE record }
  917.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  918.     pWE = *hWE;
  919.  
  920.     if (pWE->selStart == pWE->selEnd) 
  921.     {
  922.  
  923.         // { NULL SELECTION }
  924.         // { first make sure the nullStyle field contains valid information }
  925.         _WESynchNullStyle(hWE);
  926.  
  927.         // { apply style changes to the nullStyle record }
  928.         _WECopyStyle((WETextStyle *)ts, &pWE->nullStyle.runStyle, pWE->nullStyle.runStyle.tsFace, mode);
  929.  
  930.         // { if the font was altered, synchronize the keyboard script }
  931.         if (BTST(pWE->flags, weFNonRoman)) 
  932.             if (BTST(mode, kModeFont)) 
  933.             {
  934.                 fontScript = Font2Script(pWE->nullStyle.runStyle.tsFont);
  935.                 if (fontScript != GetEnvirons(smKeyScript)) 
  936.                     KeyScript(fontScript);
  937.             }
  938.     }
  939.     else
  940.     {
  941.         // { NON-EMPTY SELECTION }
  942.  
  943.         // { if undo support is enabled, save the styles of the text range to be affected }
  944.         if (BTST(pWE->flags, weFUndoSupport)) 
  945.         {
  946.             WEClearUndo(hWE);
  947.             if (WENewAction(pWE->selStart, pWE->selEnd, pWE->selEnd - pWE->selStart, weAKSetStyle,
  948.                 weAFDontSaveText + weAFDontSaveSoup, hWE, &hAction) == noErr) 
  949.                 if (WEPushAction(hAction) != noErr) 
  950.                     { ; }
  951.         }
  952.  
  953.         // { set the style of the selection range }
  954.         err = _WESetStyleRange(pWE->selStart, pWE->selEnd, mode, (WETextStyle *)ts, hWE);
  955.         if (err != noErr) 
  956.             goto cleanup;
  957.  
  958.         // { and redraw the text }
  959.         err = _WERedraw(pWE->selStart, pWE->selEnd, hWE);
  960.         if (err != noErr) 
  961.             goto cleanup;
  962.     }
  963.  
  964.     // { clear the result code }
  965.     err = noErr;
  966.  
  967. cleanup:
  968.     // { unlock the WE record }
  969.     _WESetHandleLock((Handle)hWE, saveWELock);
  970.  
  971.     // { return result code }
  972.     return err;
  973. } // { WESetStyle }
  974.  
  975. pascal OSErr WEUseStyleScrap(StScrpHandle hStyles, WEHandle hWE)
  976. {
  977.     WEPtr pWE;
  978.     Boolean saveWELock;
  979.     OSErr err;
  980.  
  981.     // { lock the WE record }
  982.     saveWELock = _WESetHandleLock((Handle)hWE, true);
  983.     pWE = *hWE;
  984.  
  985.     // { apply the style scrap to the selection range }
  986.     err = _WEApplyStyleScrap(pWE->selStart, pWE->selEnd, hStyles, hWE);
  987.     if (err != noErr) 
  988.         goto cleanup;
  989.  
  990.     // { redraw the text }
  991.     err = _WERedraw(pWE->selStart, pWE->selEnd, hWE);
  992.  
  993. cleanup:
  994.     // { unlock the WE record }
  995.     _WESetHandleLock((Handle)hWE, saveWELock);
  996.  
  997.     // { return result code }
  998.     return err;
  999. }
  1000.