home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
- #
- # Macintosh Developer Technical Support
- #
- # EditText Sample Control Panel Device
- #
- # EditCdev
- #
- # EditCdev.c - C Source
- #
- # Copyright © 1988 Apple Computer, Inc.
- # All rights reserved.
- #
- # Versions: 1.00 8/88
- # 1.10 6/92
- #
- # Components: EditCdev.p August 1, 1988
- # EditCdev.c August 1, 1988
- # EditCdev.r August 1, 1988
- # PEditCdev.make August 1, 1988
- # CEditCdev.make August 1, 1988
- # TCEditCdev.π June 12, 1992
- # TCEditCdev.π.rsrc June 12, 1992
- #
- # EditCdev is a sample Control Panel device (cdev) that
- # demonstrates the usage of the edit-related messages.
- # EditCdev demonstrates how to implement an editText item
- # in a Control Panel Device. It utilizes the new undo, cut, copy,
- # paste, and delete messages that are sent to cdevs in
- # response to user menu selections.
- #
- # It is comprised of two editText items that can be edited
- # and moved between via the mouse or tab key.
- #
- ------------------------------------------------------------------------------*/
-
- #include <Types.h>
- #include <Memory.h>
- #include <Quickdraw.h>
- #include <TextEdit.h>
- #include <Dialogs.h>
- #include <Events.h>
- #include <Devices.h>
- #include <Scrap.h>
- #include <Packages.h>
- #include <TextEdit.h>
- #include <TextUtils.h>
-
- /* Constants */
- #define textItm 1 /* first editText item in cdev */
- #define countItm 4 /* first staticText item for displaying character count */
-
- #define undoDev 9 /* cdev edit messages */
- #define cutDev 10
- #define copyDev 11
- #define pasteDev 12
- #define clearDev 13
-
- #define maxLength 50 /* maximum # of characters in each textEdit field < 32K */
-
- #define delete 0x08 /* character codes for various keys */
- #define tab 0x09
- #define leftArrow 0x1c
- #define rightArrow 0x1d
- #define upArrow 0x1e
- #define downArrow 0x1f
-
- /*
- * TYPES: Storage for CDEV - All permanent CDEV storage must be referred to by a single
- * handle, so put all permanent variables in a CDEVRec.
- */
- typedef struct CDEVRec
- {
- Boolean needUpdate;
- } CDEVRec, *CDEVPtr, **CDEVHnd;
-
-
- /*
- * PROTOTYPES
- */
- void DoEditCommand (short message, DialogPtr CPDialog);
- pascal CDEVHnd main(short message, short item, short numItems, short CPanelID,
- EventRecord *theEvent, CDEVHnd cdevStorage, DialogPtr CPDialog);
- void UpdateCharCount(DialogPtr CPDialog);
-
-
- /* This is the main dispatcher. It must be the first code in the cdev.
- * EditCdev's dispatcher responds only to the following messages from
- * the Control Panel:
- *
- * macDev - To indicate what machines it is available on.
- * nulDev - To check if the character count items need to be updated.
- * initDev - To set up some temporary storage and get the caret started.
- * keyEvtDev - To check for an edit command and do the appropriate action.
- * cutDev - To cut the current selection.
- * copyDev - To copy the current selection.
- * pasteDev - To paste the contents of the clipboard.
- * clearDev - To delete the current selection.
- *
- * The Dialog Manager's services are used to handle entry of text, selection
- * of text, editing of text, and moving between the editText items via the
- * tab key. Since the Dialog Manager handles the selection of text, we do not
- * have to be concerned with hitDev messages for the editText items. The only
- * things we have to take care of are calling the Dialog Manager editing
- * routines in response to an edit command, and getting the caret to show up
- * at the beginning. In response to an edit command that was the result of
- * a command-key equivalent, we must also eliminate the event so that it does
- * not get processed as a keyDown by the Dialog Manager. Otherwise, an 'x'
- * would show up in the editText item when the user did a command-x to cut
- * the text.
- * Also, we must be aware that the dialog manager does not keep track
- * of the length of the characters typed or pasted into the textEdit items.
- * Since the maximum number of characters that may be contained in a single
- * textEdit item is 32K, we must make sure that the user does not enter more
- * than some maximum number of characters.
- */
-
-
- pascal CDEVHnd main(short message, short item, short numItems, short CPanelID,
- EventRecord *theEvent, CDEVHnd cdevStorage, DialogPtr CPDialog)
- {
- #pragma unused (item, CPanelID) /* unused formal parameters */
-
- char tempChar;
- TEHandle myTEHandle; /* handle to the current textEdit record */
- short selLength; /* length of current selection */
-
- if (message == macDev) return((CDEVHnd) 1); /* we work on every machine */
- else if (cdevStorage != nil) {
- switch (message) {
- case initDev: /* initialize cdev */
- cdevStorage = (CDEVHnd)NewHandle(sizeof(CDEVRec)); /* create private storage */
- SelectDialogItemText(CPDialog, numItems + textItm, 0, 999); /* make caret show up */
- break;
-
- case nulDev:
- if ((**cdevStorage).needUpdate) /* character count need updating? */
- {
- UpdateCharCount(CPDialog);
- (**cdevStorage).needUpdate = false;
- }
- break;
-
- case hitDev: /* handle hit on item */
- case closeDev: /* clean up and dispose */
- case updateDev: /* handle any update drawing */
- case activDev: /* activate any needed items */
- case deactivDev: /* deactivate any needed items */
- break;
-
- case keyEvtDev: /* respond to keydown */
- tempChar = theEvent->message & charCodeMask;/* get the character, and check */
- if (theEvent->modifiers & cmdKey) /* status of command key */
- {
- message = nulDev; /* start with no message */
- theEvent->what = nullEvent; /* and empty event type */
-
- switch (tempChar) /* set appropriate message */
- {
- case 'X':
- case 'x':
- message = cutDev;
- break;
- case 'C':
- case 'c':
- message = copyDev;
- break;
- case 'V':
- case 'v':
- message = pasteDev;
- break;
- }
- DoEditCommand(message, CPDialog); /* Let edit command handler take it */
- }
- else /* not a command key */
- {
- /* We need to update the character count, but only after textEdit has */
- /* a chance to deal with it. Set a flag so that during the next nullEvent */
- /* we will process the character count update. If we call UpdateCharCount */
- /* now, we will display the incorrect count. */
- /* Also, we must make sure that we are not exceeding our character limit */
- /* with this character. (unless it is a tab or backspace, that's OK) */
-
- (**cdevStorage).needUpdate = true; /* update count during next nulDev */
-
- myTEHandle = ((DialogPeek)CPDialog)->textH;
- selLength = ((**myTEHandle).selEnd-(**myTEHandle).selStart);
-
- if ( ((**myTEHandle).teLength>=maxLength+selLength) &&
- (tempChar!=delete) && (tempChar!=tab) &&
- (tempChar!=leftArrow) && (tempChar!=rightArrow) &&
- (tempChar!=upArrow) && (tempChar!=downArrow) )
- {
- theEvent->what = nullEvent; /* trash character (textEdit never sees it) */
- SysBeep(1);
- }
- }
- break;
-
- case macDev:
- case undoDev:
- break;
-
- case cutDev:
- case copyDev:
- case pasteDev:
- case clearDev:
- DoEditCommand(message, CPDialog); /* respond to edit command */
- break;
- }
-
- return (cdevStorage);
- } /* cdevStorage != nil */
-
- return (nil); /* if cdevStorage = NIL then ControlPanel will put up memory error. */
- }
-
- /* Call the appropriate Dialog Manager routine to handle an edit command for */
- /* an editText item. It will do *ALMOST* all the work regarding the TEScrap. */
- void DoEditCommand(short message, DialogPtr CPDialog)
- {
- TEHandle myTEHandle; /* Handle to current textEdit record */
- long scrapLength; /* length of textEdit scrap */
- long freeSpace; /* amount of space before character limit */
- short selLength; /* length of current selection */
-
- myTEHandle = ((DialogPeek)CPDialog)->textH;
-
- switch (message)
- {
- case cutDev:
- DialogCut(CPDialog);
- break;
- case copyDev:
- DialogCopy(CPDialog);
- break;
- case pasteDev:
- /* Since the maximum number of characters that a textEdit structure can */
- /* handle is 32K, and the dialog manager doesn't check for overflow when */
- /* pasting, we must check for ourselves and only paste as many characters */
- /* as we have room for. */
- scrapLength = TEGetScrapLength();
- selLength = ((**myTEHandle).selEnd-(**myTEHandle).selStart);
- freeSpace = (long)(maxLength-(**myTEHandle).teLength)+selLength;
- if (freeSpace>=scrapLength) /* enough room for paste? */
- DialogPaste(CPDialog);
- else /* not enough room for paste */
- {
- SysBeep(1);
- if (freeSpace>0) /* any room for paste? */
- {
- TESetScrapLength(freeSpace); /* only paste as many characters as free */
- DialogPaste(CPDialog);
- TESetScrapLength(scrapLength); /* restore textEdit scrap length */
- }
- }
- break;
- case clearDev:
- DialogDelete(CPDialog);
- break;
- }
- UpdateCharCount(CPDialog);
- }
-
- /* Examine the appropriate structures to determine the number of characters in the */
- /* acvive TERecord and display in the corresponding static text item. */
- void UpdateCharCount(DialogPtr CPDialog)
- {
- TEHandle myTEHandle;
- short itemType;
- Handle itemHandle;
- Rect itemRect;
- Str255 text;
- short editItem;
-
- myTEHandle = ((DialogPeek)CPDialog)->textH; /* get handle to TERecord */
- HLock((Handle)myTEHandle);
- NumToString((long)((**myTEHandle).teLength), text); /* get length of text */
- HUnlock((Handle)myTEHandle);
- editItem=countItm+((DialogPeek)CPDialog)->editField; /* calculate which item to change */
- GetDialogItem(CPDialog, editItem, &itemType, &itemHandle, &itemRect);
- SetDialogItemText(itemHandle, text); /* change text item contents */
- }
-