home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Toolbox / EditTextCdev / EditCdev.p < prev    next >
Encoding:
Text File  |  1994-11-18  |  9.5 KB  |  266 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.     Types, Memory, Dialogs, QuickDraw, Events, Controls, Windows, TextEdit, 
  44.     Fonts, Lists, Menus, Resources, Scrap, ToolUtils, 
  45.     OSUtils, Files, Devices, DeskBus, DiskInit, Disks, Errors, Retrace, SegLoad, Serial,
  46.     ShutDown, Slots, Sound, Start, Timer, Packages;
  47.  
  48.  
  49. CONST
  50.  
  51.     textItm        = 1;        {first editTExt item in cdev}
  52.     countItm    = 4;        {first staticText item for displaying character count}
  53.  
  54.     maxLength    = 50;        {maximum # of characters in each textEdit field < 32K}
  55.  
  56.     delete        = $08;        {character codes for various keys}
  57.     tab            = $09;
  58.     leftArrow    = $1c;
  59.     rightArrow    = $1d;
  60.     upArrow        = $1e;
  61.     downArrow    = $1f;
  62.  
  63.  
  64. TYPE                        {Storage for CDEV - All permanent CDEV storage must be referred to}
  65.                             {by a single handle, so put all permanent variables in a CDEVRec. }
  66.     CDEVRec    = RECORD
  67.                 needUpdate    : BOOLEAN;
  68.                 END;
  69.     CDEVPtr    = ^CDEVRec;
  70.     CDEVHnd    = ^CDEVPtr;
  71.     
  72. FUNCTION TextCDEV (message, item, numItems, CPanelID: INTEGER;
  73.                                             VAR theEvent: EventRecord;
  74.                                             cdevStorage: CDEVHnd;
  75.                                             CPDialog: DialogPtr) : CDEVHnd;
  76.                                                 
  77. IMPLEMENTATION
  78.  
  79. PROCEDURE DoEditCommand (message: INTEGER; CPDialog: DialogPtr); FORWARD;
  80.  
  81. PROCEDURE UpdateCharCount(CPDialog: DialogPtr); FORWARD;
  82.  
  83. FUNCTION TextCDEV (message, item, numItems, CPanelID: INTEGER;
  84.                                             VAR theEvent: EventRecord;
  85.                                             cdevStorage: CDEVHnd;
  86.                                             CPDialog: DialogPtr) : CDEVHnd;
  87.                                             
  88. {* This is the main dispatcher. It must be the first code in the cdev.
  89.  * EditCdev's dispatcher responds only to the following messages from
  90.  * the Control Panel:
  91.  *    
  92.  *        macDev        - To indicate what machines it is available on.
  93.  *        nulDev        - To check if the character count items need to be updated.
  94.  *        initDev        - To set up some temporary storage and get the caret started.
  95.  *        keyEvtDev    - To check for an edit command and do the appropriate action.
  96.  *        cutDev        - To cut the current selection.
  97.  *        copyDev        - To copy the current selection.
  98.  *        pasteDev    - To paste the contents of the clipboard.
  99.  *        clearDev    - To delete the current selection.
  100.  *
  101.  * The Dialog Manager's services are used to handle entry of text, selection
  102.  * of text, editing of text, and moving between the editText items via the
  103.  * tab key. Since the Dialog Manager handles the selection of text, we do not
  104.  * have to be concerned with hitDev messages for the editText items. The only
  105.  * things we have to take care of are calling the Dialog Manager editing
  106.  * routines in response to an edit command, and getting the caret to show up
  107.  * at the beginning. In response to an edit command that was the result of
  108.  * a command-key equivalent, we must also eliminate the event so that it does
  109.  * not get processed as a keyDown by the Dialog Manager. Otherwise, an 'x'
  110.  * would show up in the editText item when the user did a command-x to cut
  111.  * the text.
  112.  *        Also, we must be aware that the dialog manager does not keep track
  113.  * of the length of the characters typed or pasted into the textEdit items.
  114.  * Since the maximum number of characters that may be contained in a single
  115.  * textEdit item is 32K, we must make sure that the user does not enter more
  116.  * than some maximum number of characters.}
  117.  
  118. VAR
  119.     tempChar    : CHAR;
  120.     myTEHandle    : TEHandle;        {handle to the current textEdit record}
  121.     selLength    : INTEGER;        {length of current selection}
  122. BEGIN
  123. IF message = macDev THEN TextCDEV := CDEVHnd(1)            {we work on every machine}
  124. ELSE IF cdevStorage <> NIL THEN BEGIN
  125.     CASE message OF
  126.     initDev:                                            {initialize cdev}
  127.         BEGIN
  128.         cdevStorage := CDEVHnd(NewHandle(SIZEOF(CDEVRec)));        {create private storage}
  129.         SelectDialogItemText(CPDialog, numItems + textItm, 0, 999);    {make caret show up}
  130.         END;
  131.     nulDev:
  132.         BEGIN
  133.         IF cdevStorage^^.needUpdate THEN                {character count need updating?}
  134.             BEGIN
  135.             UpdateCharCount(CPDialog);
  136.             cdevStorage^^.needUpdate := false;
  137.             END;
  138.         END;
  139.     hitDev:;
  140.     closeDev:;
  141.     updateDev:;
  142.     activDev:;
  143.     deActivDev:;
  144.     keyEvtDev:                                            {respond to key down}
  145.         BEGIN
  146.         {first, get the character}
  147.         tempChar := CHR(BAnd(theEvent.message, charCodeMask));
  148.         {then see if the command key was down}
  149.         IF BAnd(theEvent.modifiers, cmdKey) <> 0 THEN BEGIN
  150.             message := nulDev;                            {start off with no message}
  151.             theEvent.what := nullEvent;                    {wipe out event}
  152.             CASE tempChar OF                            {set appropriate message}
  153.                 'X','x':
  154.                     message := cutDev;
  155.                 'C','c':
  156.                     message := copyDev;
  157.                 'V','v':
  158.                     message := pasteDev;
  159.                 END;
  160.             DoEditCommand(message, CPDialog);            {let edit command handler take it}
  161.             END
  162.         ELSE BEGIN    {not a command key}
  163.                     {   We need to update the character count, but only after textEdit has    }
  164.                     { a chance to deal with it.  Set a flag so that during the next nullEvent }
  165.                     { we will process the character count update.  If we call UpdateCharCount }
  166.                     { now, we will display the incorrect count.                                     }
  167.                     {   Also, we must make sure that we are not exceeding our character limit }
  168.                     { with this character.  (unless it is a tab or backspace, that's OK)      }
  169.                     
  170.                     cdevStorage^^.needUpdate := true;        {update count during next nulDev}
  171.                     
  172.                     myTEHandle := DialogPeek(CPDialog)^.textH;
  173.                     selLength := (myTEHandle^^.selEnd-myTEHandle^^.selStart);
  174.  
  175.                     IF (myTEHandle^^.teLength>=maxLength+selLength) AND
  176.                         (ORD(tempChar)<>delete) AND (ORD(tempChar)<>tab) AND
  177.                         (ORD(tempChar)<>rightArrow) AND (ORD(tempChar)<>leftArrow) AND
  178.                         (ORD(tempChar)<>upArrow) AND (ORD(tempChar)<>downArrow) THEN BEGIN
  179.                         theEvent.what := nullEvent;    {trash character (so textEdit never sees it)}
  180.                         SysBeep(1);
  181.                         END;
  182.             END;
  183.         END;
  184.     macDev:;
  185.     undoDev:;
  186.     cutDev, copyDev, pasteDev, clearDev:
  187.         DoEditCommand(message, CPDialog);                {respond to edit command}
  188.     END;  {CASE message}
  189.     TextCDEV := cdevStorage; {if cdevStorage = NIL then ControlPanel will put up memory error}
  190.     END;  {cdevStorage <> NIL}
  191. END; {TextCDEV}
  192.  
  193. PROCEDURE DoEditCommand (message: INTEGER; CPDialog: DialogPtr);
  194.  
  195. { Call the appropriate Dialog Manager routine to handle an edit command for }
  196. { an editText item. It will do *ALMOST* all the work regarding the TEScrap. }
  197.  
  198. VAR 
  199.     myTEHandle    : TEHandle;        {Handle to current textEdit record}
  200.     scrapLength    : LONGINT;        {length of textEdit scrap}
  201.     freeSpace    : LONGINT;        {amount of space before character limit}
  202.     selLength    : INTEGER;        {length of current selection}
  203. BEGIN
  204. myTEHandle := DialogPeek(CPDialog)^.textH;
  205.  
  206. CASE message OF
  207.     cutDev:
  208.         DialogCut(CPDialog);
  209.     copyDev:
  210.         DialogCopy(CPDialog);
  211.     pasteDev:
  212.         { Since the maximum number of characters that a textEdit structure can   }
  213.         { handle is 32K, and the dialog manager doesn't check for overflow when  }
  214.         { pasting, we must check for ourselves and only paste as many characters }
  215.         { as we have room for. }
  216.     BEGIN
  217.         scrapLength := TEGetScrapLength;
  218.         selLength := (myTEHandle^^.selEnd)-(myTEHandle^^.selStart);
  219.         freeSpace := LONGINT(maxLength-(myTEHandle^^.teLength)+selLength);
  220.         IF freeSpace>=scrapLength THEN    {enough room for paste?}
  221.             DialogPaste(CPDialog)
  222.         ELSE BEGIN                        {not enough room for paste}
  223.             SysBeep(1);
  224.             IF freeSpace>0 THEN BEGIN    {any room for paste?}
  225.                 TESetScrapLength(freeSpace);    {only paste as many characters as free}
  226.                 DialogPaste(CPDialog);
  227.                 TESetScrapLength(scrapLength);    {restore textEdit scrap length}
  228.             END;
  229.         END;
  230.     END;
  231.     clearDev:
  232.         DialogDelete(CPDialog);
  233.     END;
  234.     UpdateCharCount(CPDialog);
  235. END; {DoEditCommand}
  236.  
  237.  
  238. { Examine the appropriate structures to determine the number of characters in the    }
  239. { acvive TERecord and display in the corresponding static text item.                }
  240. { Note that since we can only have one code segment in a CDEV, we must use the $R-    }
  241. { directive to tell the compiler not to do string range checking.  When the            }
  242. { compiler does checking, it attempts to load the checking routines from PasLib.o,    }
  243. { and into another segment.     An alternate solution is to force the linker to put    }
  244. { the string length checking routines into the main segment with the -sn option.    }
  245.  
  246. {$R-}    {Turns off string range checking}
  247.  
  248. PROCEDURE UpdateCharCount(CPDialog: DialogPtr);
  249. VAR
  250.     myTEHandle    : TEHandle;
  251.     itemType    : INTEGER;
  252.     itemHandle    : Handle;
  253.     itemRect    : Rect;
  254.     text        : Str255;
  255.     editItem    : INTEGER;
  256. BEGIN
  257.     myTEHandle := DialogPeek(CPDialog)^.textH;             {get handle to TERecord}
  258.     HLock(Handle(myTEHandle));
  259.     NumToString(LONGINT(myTEHandle^^.teLength), text);     {get length of text}
  260.     HUnlock(Handle(myTEHandle));
  261.     editItem:=countItm+DialogPeek(CPDialog)^.editField;  {calculate which item to change}
  262.     GetDialogItem(CPDialog, editItem, itemType, itemHandle, itemRect);
  263.     SetDialogItemText(itemHandle, text);                             {change text item contents}
  264. END;
  265. END.  {EditTextCDEV}
  266.