home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Macintosh Sample Code / SC.010.EditTextCdev / EditCdev.p < prev    next >
Encoding:
Text File  |  1992-06-12  |  9.3 KB  |  264 lines  |  [TEXT/MPS ]

  1. {------------------------------------------------------------------------------
  2. #
  3. #    Macintosh Developer Technical Support
  4. #
  5. #    EditText Sample Control Panel Device
  6. #
  7. #    EditCdev
  8. #
  9. #    EditCdev.p    -    Pascal Source
  10. #
  11. #    Copyright © 1988 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    1.00                8/88
  15. #                1.10                6/92
  16. #
  17. #    Components:    EditCdev.p            August 1, 1988
  18. #                EditCdev.c            August 1, 1988
  19. #                EditCdev.r            August 1, 1988
  20. #                PEditCdev.make        August 1, 1988
  21. #                CEditCdev.make        August 1, 1988
  22. #                TCEditCdev.π        June 12, 1992
  23. #                TCEditCdev.π.rsrc    June 12, 1992
  24. #
  25. #    EditCdev is a sample Control Panel device (cdev) that 
  26. #    demonstrates the usage of the edit-related messages.  
  27. #    EditCdev demonstrates how to implement an editText item
  28. #    in a Control Panel Device.  It utilizes the new undo, cut, copy,
  29. #    paste, and delete messages that are sent to cdevs in
  30. #    response to user menu selections.
  31. #
  32. #    It is comprised of two editText items that can be edited 
  33. #    and moved between via the mouse or tab key.
  34. #
  35. ------------------------------------------------------------------------------}
  36.  
  37. UNIT EditTextCDEV;
  38.  
  39. INTERFACE
  40.  
  41. USES
  42.  
  43.     MemTypes, Memory, Dialogs, QuickDraw, OSIntf,
  44.     ToolIntf, Packages, PackIntf, TextEdit;
  45.  
  46.  
  47. CONST
  48.  
  49.     textItm        = 1;        {first editTExt item in cdev}
  50.     countItm    = 4;        {first staticText item for displaying character count}
  51.  
  52.     maxLength    = 50;        {maximum # of characters in each textEdit field < 32K}
  53.  
  54.     delete        = $08;        {character codes for various keys}
  55.     tab            = $09;
  56.     leftArrow    = $1c;
  57.     rightArrow    = $1d;
  58.     upArrow        = $1e;
  59.     downArrow    = $1f;
  60.  
  61.  
  62. TYPE                        {Storage for CDEV - All permanent CDEV storage must be referred to}
  63.                             {by a single handle, so put all permanent variables in a CDEVRec. }
  64.     CDEVRec    = RECORD
  65.                 needUpdate    : BOOLEAN;
  66.                 END;
  67.     CDEVPtr    = ^CDEVRec;
  68.     CDEVHnd    = ^CDEVPtr;
  69.     
  70. FUNCTION TextCDEV (message, item, numItems, CPanelID: INTEGER;
  71.                                             VAR theEvent: EventRecord;
  72.                                             cdevStorage: CDEVHnd;
  73.                                             CPDialog: DialogPtr) : CDEVHnd;
  74.                                                 
  75. IMPLEMENTATION
  76.  
  77. PROCEDURE DoEditCommand (message: INTEGER; CPDialog: DialogPtr); FORWARD;
  78.  
  79. PROCEDURE UpdateCharCount(CPDialog: DialogPtr); FORWARD;
  80.  
  81. FUNCTION TextCDEV (message, item, numItems, CPanelID: INTEGER;
  82.                                             VAR theEvent: EventRecord;
  83.                                             cdevStorage: CDEVHnd;
  84.                                             CPDialog: DialogPtr) : CDEVHnd;
  85.                                             
  86. {* This is the main dispatcher. It must be the first code in the cdev.
  87.  * EditCdev's dispatcher responds only to the following messages from
  88.  * the Control Panel:
  89.  *    
  90.  *        macDev        - To indicate what machines it is available on.
  91.  *        nulDev        - To check if the character count items need to be updated.
  92.  *        initDev        - To set up some temporary storage and get the caret started.
  93.  *        keyEvtDev    - To check for an edit command and do the appropriate action.
  94.  *        cutDev        - To cut the current selection.
  95.  *        copyDev        - To copy the current selection.
  96.  *        pasteDev    - To paste the contents of the clipboard.
  97.  *        clearDev    - To delete the current selection.
  98.  *
  99.  * The Dialog Manager's services are used to handle entry of text, selection
  100.  * of text, editing of text, and moving between the editText items via the
  101.  * tab key. Since the Dialog Manager handles the selection of text, we do not
  102.  * have to be concerned with hitDev messages for the editText items. The only
  103.  * things we have to take care of are calling the Dialog Manager editing
  104.  * routines in response to an edit command, and getting the caret to show up
  105.  * at the beginning. In response to an edit command that was the result of
  106.  * a command-key equivalent, we must also eliminate the event so that it does
  107.  * not get processed as a keyDown by the Dialog Manager. Otherwise, an 'x'
  108.  * would show up in the editText item when the user did a command-x to cut
  109.  * the text.
  110.  *        Also, we must be aware that the dialog manager does not keep track
  111.  * of the length of the characters typed or pasted into the textEdit items.
  112.  * Since the maximum number of characters that may be contained in a single
  113.  * textEdit item is 32K, we must make sure that the user does not enter more
  114.  * than some maximum number of characters.}
  115.  
  116. VAR
  117.     tempChar    : CHAR;
  118.     myTEHandle    : TEHandle;        {handle to the current textEdit record}
  119.     selLength    : INTEGER;        {length of current selection}
  120. BEGIN
  121. IF message = macDev THEN TextCDEV := CDEVHnd(1)            {we work on every machine}
  122. ELSE IF cdevStorage <> NIL THEN BEGIN
  123.     CASE message OF
  124.     initDev:                                            {initialize cdev}
  125.         BEGIN
  126.         cdevStorage := CDEVHnd(NewHandle(SIZEOF(CDEVRec)));        {create private storage}
  127.         SelIText(CPDialog, numItems + textItm, 0, 999);    {make caret show up}
  128.         END;
  129.     nulDev:
  130.         BEGIN
  131.         IF cdevStorage^^.needUpdate THEN                {character count need updating?}
  132.             BEGIN
  133.             UpdateCharCount(CPDialog);
  134.             cdevStorage^^.needUpdate := false;
  135.             END;
  136.         END;
  137.     hitDev:;
  138.     closeDev:;
  139.     updateDev:;
  140.     activDev:;
  141.     deActivDev:;
  142.     keyEvtDev:                                            {respond to key down}
  143.         BEGIN
  144.         {first, get the character}
  145.         tempChar := CHR(BAnd(theEvent.message, charCodeMask));
  146.         {then see if the command key was down}
  147.         IF BAnd(theEvent.modifiers, cmdKey) <> 0 THEN BEGIN
  148.             message := nulDev;                            {start off with no message}
  149.             theEvent.what := nullEvent;                    {wipe out event}
  150.             CASE tempChar OF                            {set appropriate message}
  151.                 'X','x':
  152.                     message := cutDev;
  153.                 'C','c':
  154.                     message := copyDev;
  155.                 'V','v':
  156.                     message := pasteDev;
  157.                 END;
  158.             DoEditCommand(message, CPDialog);            {let edit command handler take it}
  159.             END
  160.         ELSE BEGIN    {not a command key}
  161.                     {   We need to update the character count, but only after textEdit has    }
  162.                     { a chance to deal with it.  Set a flag so that during the next nullEvent }
  163.                     { we will process the character count update.  If we call UpdateCharCount }
  164.                     { now, we will display the incorrect count.                                     }
  165.                     {   Also, we must make sure that we are not exceeding our character limit }
  166.                     { with this character.  (unless it is a tab or backspace, that's OK)      }
  167.                     
  168.                     cdevStorage^^.needUpdate := true;        {update count during next nulDev}
  169.                     
  170.                     myTEHandle := DialogPeek(CPDialog)^.textH;
  171.                     selLength := (myTEHandle^^.selEnd-myTEHandle^^.selStart);
  172.  
  173.                     IF (myTEHandle^^.teLength>=maxLength+selLength) AND
  174.                         (ORD(tempChar)<>delete) AND (ORD(tempChar)<>tab) AND
  175.                         (ORD(tempChar)<>rightArrow) AND (ORD(tempChar)<>leftArrow) AND
  176.                         (ORD(tempChar)<>upArrow) AND (ORD(tempChar)<>downArrow) THEN BEGIN
  177.                         theEvent.what := nullEvent;    {trash character (so textEdit never sees it)}
  178.                         SysBeep(1);
  179.                         END;
  180.             END;
  181.         END;
  182.     macDev:;
  183.     undoDev:;
  184.     cutDev, copyDev, pasteDev, clearDev:
  185.         DoEditCommand(message, CPDialog);                {respond to edit command}
  186.     END;  {CASE message}
  187.     TextCDEV := cdevStorage; {if cdevStorage = NIL then ControlPanel will put up memory error}
  188.     END;  {cdevStorage <> NIL}
  189. END; {TextCDEV}
  190.  
  191. PROCEDURE DoEditCommand (message: INTEGER; CPDialog: DialogPtr);
  192.  
  193. { Call the appropriate Dialog Manager routine to handle an edit command for }
  194. { an editText item. It will do *ALMOST* all the work regarding the TEScrap. }
  195.  
  196. VAR 
  197.     myTEHandle    : TEHandle;        {Handle to current textEdit record}
  198.     scrapLength    : LONGINT;        {length of textEdit scrap}
  199.     freeSpace    : LONGINT;        {amount of space before character limit}
  200.     selLength    : INTEGER;        {length of current selection}
  201. BEGIN
  202. myTEHandle := DialogPeek(CPDialog)^.textH;
  203.  
  204. CASE message OF
  205.     cutDev:
  206.         DlgCut(CPDialog);
  207.     copyDev:
  208.         DlgCopy(CPDialog);
  209.     pasteDev:
  210.         { Since the maximum number of characters that a textEdit structure can   }
  211.         { handle is 32K, and the dialog manager doesn't check for overflow when  }
  212.         { pasting, we must check for ourselves and only paste as many characters }
  213.         { as we have room for. }
  214.     BEGIN
  215.         scrapLength := TEGetScrapLen;
  216.         selLength := (myTEHandle^^.selEnd)-(myTEHandle^^.selStart);
  217.         freeSpace := LONGINT(maxLength-(myTEHandle^^.teLength)+selLength);
  218.         IF freeSpace>=scrapLength THEN    {enough room for paste?}
  219.             DlgPaste(CPDialog)
  220.         ELSE BEGIN                        {not enough room for paste}
  221.             SysBeep(1);
  222.             IF freeSpace>0 THEN BEGIN    {any room for paste?}
  223.                 TESetScrapLen(freeSpace);    {only paste as many characters as free}
  224.                 DlgPaste(CPDialog);
  225.                 TESetScrapLen(scrapLength);    {restore textEdit scrap length}
  226.             END;
  227.         END;
  228.     END;
  229.     clearDev:
  230.         DlgDelete(CPDialog);
  231.     END;
  232.     UpdateCharCount(CPDialog);
  233. END; {DoEditCommand}
  234.  
  235.  
  236. { Examine the appropriate structures to determine the number of characters in the    }
  237. { acvive TERecord and display in the corresponding static text item.                }
  238. { Note that since we can only have one code segment in a CDEV, we must use the $R-    }
  239. { directive to tell the compiler not to do string range checking.  When the            }
  240. { compiler does checking, it attempts to load the checking routines from PasLib.o,    }
  241. { and into another segment.     An alternate solution is to force the linker to put    }
  242. { the string length checking routines into the main segment with the -sn option.    }
  243.  
  244. {$R-}    {Turns off string range checking}
  245.  
  246. PROCEDURE UpdateCharCount(CPDialog: DialogPtr);
  247. VAR
  248.     myTEHandle    : TEHandle;
  249.     itemType    : INTEGER;
  250.     itemHandle    : Handle;
  251.     itemRect    : Rect;
  252.     text        : Str255;
  253.     editItem    : INTEGER;
  254. BEGIN
  255.     myTEHandle := DialogPeek(CPDialog)^.textH;             {get handle to TERecord}
  256.     HLock(Handle(myTEHandle));
  257.     NumToString(LONGINT(myTEHandle^^.teLength), text);     {get length of text}
  258.     HUnlock(Handle(myTEHandle));
  259.     editItem:=countItm+DialogPeek(CPDialog)^.editField;  {calculate which item to change}
  260.     GetDItem(CPDialog, editItem, itemType, itemHandle, itemRect);
  261.     SetIText(itemHandle, text);                             {change text item contents}
  262. END;
  263. END.  {EditTextCDEV}
  264.