|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T
Length: 79912 (0x13828) Types: TextFile Names: »TextEdit.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦526ad3590⟧ »EUUGD11/gnu-31mar87/X.V10.R4.tar.Z« └─⟦2109abc41⟧ └─⟦this⟧ »./X.V10R4/Toolkit/Xr/src/Xrlib/Editor/TextEdit.c«
/* * $Source: /u1/Xr/src/Xrlib/Editor/RCS/TextEdit.c,v $ * $Header: TextEdit.c,v 1.1 86/12/17 09:05:45 swick Exp $ */ #ifndef lint static char *rcsid_TextEdit_c = "$Header: TextEdit.c,v 1.1 86/12/17 09:05:45 swick Exp $"; #endif lint #include <Xr/xr-copyright.h> /* $Header: TextEdit.c,v 1.1 86/12/17 09:05:45 swick Exp $ */ /* Copyright 1986, Hewlett-Packard Company */ /* Copyright 1986, Massachussetts Institute of Technology */ static char rcsid[] = "$Header: TextEdit.c,v 1.1 86/12/17 09:05:45 swick Exp $"; /*************************************<+>************************************* ***************************************************************************** ** ** File: TextEdit.c ** ** Project: X-ray Toolbox ** ** Description: ** Source code for the X-ray text edit field editor. ** ** ** ------------------------ MODIFICATION RECORD ------------------------ * * $Log: TextEdit.c,v $ * Revision 1.1 86/12/17 09:05:45 swick * Initial revision * * Revision 7.0 86/11/13 08:28:31 08:28:31 fred () * Final QA Release * * Revision 6.0 86/11/10 15:37:01 15:37:01 fred () * QA #2 release * * Revision 5.8 86/11/10 09:18:03 09:18:03 fred () * Added check for '\n', in addition to '\r' and RETURN_KEY in * teTraversalEvent(). * * Revision 5.7 86/11/07 14:24:15 14:24:15 fred () * Added new copyright message. * * Revision 5.6 86/11/06 07:00:59 07:00:59 fred () * Added text string redraw to teActivate(), to handle when the * application changes the string value during temporary break event. * * Revision 5.5 86/11/05 14:51:42 14:51:42 fred () * Added check for cursor past the end of the string. * * Revision 5.4 86/11/05 09:34:09 09:34:09 fred () * Fixed bug which prevented handling of 8 bit characters. * * Revision 5.3 86/11/05 08:49:40 08:49:40 fred () * Now only handles input events if they occurred in the window in which * the editor instance was created. * * Revision 5.2 86/11/03 11:46:19 11:46:19 fred () * Added fix to treat DEL the same as BACKSPACE. * * Revision 5.1 86/10/30 13:30:51 13:30:51 fred () * Fixed bug in handling of RETURN and TAB keys for non-HP keyboards. * * Revision 5.0 86/10/28 08:37:49 08:37:49 fred () * QA #1.1 release * * Revision 4.3 86/10/27 15:50:25 15:50:25 fred () * Fixed bug introduced by previous update. * * Revision 4.2 86/10/27 13:49:53 13:49:53 fred () * Updated to match new XrInputMap() syntax. * * Revision 4.1 86/10/23 09:10:43 09:10:43 fred () * Removed unused variables. * * Revision 4.0 86/10/20 12:14:33 12:14:33 fred () * QA #1 release * * Revision 3.6 86/10/16 09:19:16 09:19:16 fred () * Performance enhanced: added use of register variables. * * Revision 3.5 86/10/15 09:15:40 09:15:40 fred () * Now treat control characters as unknown events, and return them to * the application; this allows keyboard equivalents in menus. * * Revision 3.4 86/10/13 10:07:16 10:07:16 fred () * Added use of the default tile, if needed. * * Revision 3.3 86/10/09 07:56:02 07:56:02 fred () * Added default color check to create routine. * * Revision 3.2 86/10/07 16:50:16 16:50:16 fred () * Upgraded to use new XrMapButton() calling sequence. * * Revision 3.1 86/10/07 16:06:33 16:06:33 fred () * Added code to free up the background tile at MSG_FREE time, * and now set 'value3' field when traversal event occurs. * * Revision 3.0 86/10/02 16:02:22 16:02:22 fred () * Alpha release set to 3.0 * * Revision 2.7 86/10/01 15:37:27 15:37:27 fred () * Updated several procedure headers. * * Revision 2.6 86/10/01 08:41:44 08:41:44 fred () * Changed to use the input translation routines; application must * now call XrInputInit(display type) before using a text editor. * * Revision 2.5 86/09/29 12:52:37 12:52:37 fred () * Changed processTextEdit() so that an unknown event received while * a field is inactive causes NULL to be returned, instead of having * the event treated as an unknown event. * * Revision 2.4 86/09/29 12:01:59 12:01:59 fred () * Filled in the procedure headers. * * Revision 2.3 86/09/29 07:07:31 07:07:31 fred () * Added the variable width cell size parameter. * * Revision 2.2 86/09/25 09:49:16 09:49:16 fred () * First full functionality version. * * Revision 2.1 86/09/19 07:13:33 07:13:33 fred () * Added a check for XrVISIBLE before doing any drawing. * * Revision 2.0 86/09/16 08:12:26 08:12:26 fred () * No change; updated to 2.0 to match revision of other sources. * * Revision 1.1 86/09/03 13:58:45 13:58:45 fred () * Initial revision * * ***************************************************************************** *************************************<+>*************************************/ #include <X/Xlib.h> #include <Xr/defs.h> #include <Xr/types.h> #include <Xr/in_types.h> #include <ctype.h> #include <Xr/keycode.h> extern INT32 teFreeMemory(); extern INT32 createTextEdit(); extern INT32 drawTextEdit(); extern xrEditor * processTextEdit(); extern xrEditor * teMOVE_handler(); extern xrEditor * teRESIZE_handler(); extern xrEditor * teREDRAW_handler(); extern xrEditor * teINSERTMODE_handler(); extern xrEditor * teActivate(); #define XrINITANDDRAWALL 0x00 #define XrSTRINGONLY 0x01 #define XrALLOTHERPARTS 0x02 #define XrALLCOMPONENTS (XrSTRINGONLY | XrALLOTHERPARTS) #define BORDER 3 #define PADDING 2 \f /*************************************<->************************************* * * XrTextEdit (textEdit, message, data) * * xrEditor * textEdit; * INT32 message; * INT8 * data; * * Description: * ----------- * This is the main handler routine for the text edit field editor. * It takes each action request issued by an application, verifies * that the editor can handle it, and then calls the appropriate * handling routine. * * * Inputs: * ------ * textEdit = For all messages by MSG_NEW and MSG_SIZE, this must * contain the editor instance pointer for the instance * which is to be operated upon. * * message = This specifies the action to be taken by the editor. * * data = This is the message specific data. It may be a scalar, * a pointer, or not used, depending upon the action requested. * * Outputs: * ------- * Upon successful completion, all messages will return a non-NULL * value (normally the instance pointer). Additional data may * be returned by certain messages. * * Upon failure, NULL will be returned, and xrErrno set. * * Procedures Called * ----------------- * _MsgNew() [MsgCommon.c] * _MsgFree() [MsgCommon.c] * _MsgGetState() [MsgCommon.c] * _MsgSetState() [MsgCommon.c] * XrCopyRect() [calc.c] * sizeTextEdit() * drawTextEdit() * processTextEdit() * teActivate() * teMOVE_handler() * teRESIZE_handler() * teREDRAW_handler() * teINSERTMODE_handler() * *************************************<->***********************************/ xrEditor * XrTextEdit (textEdit, message, data) register xrEditor * textEdit; INT32 message; INT8 * data; { /* Determine the action being requested */ switch (message) { case MSG_NEW: { /* * Create a new instance of this editor. * The 'textEdit' parameter is unused, but the 'data' * parameter must point to a filled out instance of * the 'xrTextEditInfo' structure, which describes the * instance which is to be created. */ return ((xrEditor *)_MsgNew (textEdit, data, sizeof(xrTextEditData), createTextEdit, drawTextEdit, teFreeMemory, XrTextEdit, XrINITANDDRAWALL)); } case MSG_FREE: { /* * Destroy the specified editor instance. * The only parameter of instance is 'textEdit', which * contains the editor instance pointer for the instance * which is to be destroyed. */ return ((xrEditor *) _MsgFree (textEdit, teFreeMemory)); } case MSG_GETSTATE: { /* * Return the current state flags associated with the * specified text edit instance. The 'textEdit' parameter * contains the editor instance pointer, and the 'data' * parameter points to an INT8 value, into which the * state flag values will be placed. */ return ((xrEditor *) _MsgGetState (textEdit, data)); } case MSG_SETSTATE: { /* * Change the state flags associated with a particular text * edit instance. The 'textEdit' parameter contains the * editor instance pointer for the instance to be modified, * while the 'data' parameter is interpreted as an INT8 * value, containing the new state flag values. */ return ((xrEditor *) _MsgSetState (textEdit, data, drawTextEdit, XrINITANDDRAWALL)); } case MSG_GETITEMCOUNT: { /* * Return the number of text edit fields in the specified * instance. The 'textEdit' parameter contains the editor * instance pointer, and the 'data' parameter must point to * an INT32 value, into which the field count will be placed. */ INT32 * countPtr = (INT32 *) data; if (textEdit == NULL) { xrErrno = XrINVALIDID; return ((xrEditor *) NULL); } else if (countPtr == NULL) { xrErrno = XrINVALIDPTR; return ((xrEditor *) NULL); } *countPtr = 1; return (textEdit); } case MSG_GETITEMRECTS: { /* * Fill the array passed in by the application, with the * rectangle information describing the text edit region * for the specified instance. The 'textEdit' parameter * must contain the editor instance pointer, while the * 'data' parameter must point to an instance of the * 'RECTANGLE' structure, into which the instance's editor * rectangle information will be placed. */ xrTextEditData * teDataPtr; if (textEdit == NULL) { xrErrno = XrINVALIDID; return ((xrEditor *) NULL); } else if (data == NULL) { xrErrno = XrINVALIDPTR; return ((xrEditor *) NULL); } teDataPtr = (xrTextEditData *) textEdit->editorData; XrCopyRect (&teDataPtr->teFrameRect, data); return (textEdit); } case MSG_SIZE: { /* * Return the size of the rectangle needed to enclose * an instance of this editor, using the specifications * passed in by the application program. The 'textEdit' * parameter is unused, while the 'data' parameter must * point to a partially filled out instance of the * 'xrTextEditInfo' structure. */ xrTextEditInfo * teInfoPtr = (xrTextEditInfo *) data; if (teInfoPtr == NULL) { xrErrno = XrINVALIDPTR; return ((xrEditor *) NULL); } return((xrEditor *) sizeTextEdit (teInfoPtr, &teInfoPtr->editorRect)); } case MSG_MOVE: { /* * Relocate an instance of the text editor to a new location. * The 'textEdit' parameter must contain the editor instance * pointer, while the 'data' parameter must point to an * instance of the 'POINT' structure, which contains the new * editor rectangle origin. */ return ((xrEditor *) teMOVE_handler (textEdit, data)); } case MSG_RESIZE: { /* * Resize an existing instance of the text editor. * The 'textEdit' parameter must contain the editor instance * pointer, while the 'data' parameter must point to an * instance of the 'RECTANGLE' structure, which contains the new * editor rectangle size and origin information. */ return ((xrEditor *) teRESIZE_handler (textEdit, data)); } case MSG_REDRAW: { /* * Redraw the editor, to match new value. * The 'textEdit' parameter must contain the editor instance * pointer, while the 'data' parameter will be interpreted * as an INT32 value, specifying the type of redraw to perform. */ return ((xrEditor *) teREDRAW_handler (textEdit, (INT32) data)); } case MSG_INSERTMODE: { /* * Change the character insertion mode. * The 'textEdit' parameter must contain the editor instance * pointer, while the 'data' parameter will be interpreted * as an INT8 value, specifying the type of insert mode * under which the instance will operate. */ return ((xrEditor *) teINSERTMODE_handler (textEdit, (INT8) data)); } case MSG_DEACTIVATE: { /* * Force the text edit field inactive. * The 'textEdit' parameter must contain the editor instance * pointer; the 'data' parameter is unused. */ xrTextEditData * teDataPtr; if (textEdit == NULL) { xrErrno = XrINVALIDID; return ((xrEditor *) NULL); } teDataPtr = (xrTextEditData *) textEdit->editorData; if (teDataPtr->teCursorOn) { teDataPtr->teCursorOn = FALSE; drawTextEdit (textEdit, XrINITANDDRAWALL); } return (textEdit); } case MSG_ACTIVATE: { /* * Activate the instance, and start waiting for an * input event to be received. The 'textEdit' parameter * must contain the editor instance pointer, while the * 'data' parameter is unused. */ return (teActivate (textEdit)); } case MSG_EDIT: { /* * Process the incoming keystroke, and generate a return * keystroke, to indicate to the application program how the * editor instance was modified. The 'textEdit' parameter * must contain the editor instance pointer; the 'data' parameter * must point to an XEvent structure, containing some X event. */ if ((textEdit == NULL) || (data == NULL) || ((textEdit->editorState & (XrSENSITIVE | XrVISIBLE)) != (XrSENSITIVE | XrVISIBLE))) return ((xrEditor *) NULL); return (processTextEdit (textEdit, data)); } default: /* All other commands are invalid */ xrErrno = XrINVALIDMSG; return ((xrEditor *)NULL); } /* end of switch */ } /* end of XrTextEdit() */ \f /*************************************<->************************************* * * teFreeMemory (teDataPtr) * * Description: * ----------- * xxxxxxxxxxxxxxxxxxxxxxx * * * Inputs: * ------ * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Outputs: * ------- * xxxxxxxxxxxx = xxxxxxxxxxxxx * * Procedures Called * ----------------- * *************************************<->***********************************/ static INT32 teFreeMemory (teDataPtr) xrTextEditData * teDataPtr; { if (teDataPtr->teTileId != xrDefaultTile) XFreePixmap (teDataPtr->teTileId); } \f /*************************************<->************************************* * * INT32 * sizeTextEdit (teInfoPtr, rectPtr) * * xrTextEditInfo * teInfoPtr; * RECTANGLE * rectPtr; * * Description: * ----------- * This routine takes the text edit specifications, contained in the * 'info' structure pointed to by the 'teInfoPtr' parameter, and * calculates the size of the smallest rectangle needed to contain * the instance. * * * Inputs: * ------ * teInfoPtr = This points to an 'info' structure, containing the * specifics describing the hypothetical instance. Only * the 'cellWidth', 'editorFont', 'maxChars' and 'label' * fields need to be initialized. * * rectPtr = The minimally sized 0-based rectangle needed to contain * the instance will be returned in the structure pointed to * by this parameter. * * Outputs: * ------- * Upon successful completion, TRUE is returned, along with the * rectangle definition. * * Upon failure, FALSE is returned, and xrErrno is set. * * Procedures Called * ----------------- * _XrTextInfo() [textUtil.c] * XrStringWidth() [utilities.c] * XrSetRect() [calc.c] * *************************************<->***********************************/ static INT32 sizeTextEdit (teInfoPtr, rectPtr) xrTextEditInfo * teInfoPtr; RECTANGLE * rectPtr; { INT16 height; INT16 width; INT16 stringWidth; INT16 labelWidth; FontInfo * fontPtr; xrTextInfo fontData; INT8 cellWidth; /* Request extra information for the font we will be using. */ fontPtr = (teInfoPtr->editorFont) ? teInfoPtr->editorFont : xrBaseFontInfo; _XrTextInfo (fontPtr, &fontData); /* Determine what character cell width to use */ if (teInfoPtr->cellWidth == XrMAXWIDTH) cellWidth = fontData.maxWidth; else if (teInfoPtr->cellWidth == XrAVGWIDTH) cellWidth = fontData.avgWidth; else if (teInfoPtr->cellWidth < 0) { xrErrno = XrPARMOUTOFRANGE; return (FALSE); } else cellWidth = teInfoPtr->cellWidth; /* * Calculate the width of the label and the largest * text string, including space for the cursor. */ stringWidth = (teInfoPtr->maxChars * cellWidth) + XrStringWidth (fontPtr, " ", 1, 0, 0) + 1; if (teInfoPtr->label) labelWidth = XrStringWidth (fontPtr, teInfoPtr->label, XrNULLTERMINATED, 0, 0); else labelWidth = 0; /* * We now have enough information to calculate the editor rectangle. * * width = label width + labelPadding + border width + padding + * string width + padding + border width. * [ For the width, padding = 2 pixels ] * * height = border height + padding + font height + padding + * border height. * [ For the height, padding = font Leading value ] */ width = labelWidth + fontData.avgWidth + BORDER + PADDING + stringWidth + PADDING + BORDER; height = BORDER + fontData.leading + fontData.ascent + fontData.descent + fontData.leading + BORDER; XrSetRect (rectPtr, 0, 0, width, height); return (TRUE); } \f /*************************************<->************************************* * * createTextEdit (teDataPtr, teInfoPtr, message) * * xrTextEditData * teDataPtr; * xrTextEditInfo * teInfoPtr; * INT32 message; * * Description: * ----------- * This routine is used both during the creation of a new text edit * instance, and during the resizing of an existing instance. In * either case, it expects the 'teInfoPtr' parameter to point to * a filled out instance of the the 'info' structure. Using this * information, it will calculate the size and location of each * component of the instance being created/resized; all of this * information will be stored in the 'data' structure pointed to * by the 'teDataPtr' parameter. * * * Inputs: * ------ * teDataPtr = This points to the 'data' structure, into which the * component information is to be saved. * * teInfoPtr = This must point to an instance of the 'info' structure. * In the case of MSG_NEW, it must be completely filled out; * for MSG_RESIZE, only the 'editorRect', 'editorFont', * 'label', 'maxChars', 'labelPosition' and 'cellWidth' * fields must be filled. * * message = This must be set to either MSG_NEW or MSG_RESIZE, depending * upon whether the instance is being created or resized. * * Outputs: * ------- * Upon successful completion, TRUE is returned, and the 'data' * structure is filled out. * * Upon failure, FALSE is returned, and xrErrno is set. * * Procedures Called * ----------------- * _XrTextInfo() [textUtil.c] * XrSTringWidth() [utilities.c] * XrSetPt() [calc.c] * XrSetRect() [calc.c] * XrResource() [resource.c] * XMakePixmap() [libX.a] * sizeTextEdit() * *************************************<->***********************************/ static INT32 createTextEdit (teDataPtr, teInfoPtr, message) register xrTextEditData * teDataPtr; register xrTextEditInfo * teInfoPtr; INT32 message; { register RECTANGLE * editorRect; INT16 textBaseLine; INT16 maxTextWidth; FontInfo * fontPtr; xrResourceInfo bitmapInfo; RECTANGLE workRect; INT16 x; INT16 width; if (message == MSG_NEW) { /* Validate incoming parameters */ if (teInfoPtr->string == NULL) { xrErrno = XrINVALIDPTR; return (FALSE); } else if (teInfoPtr->maxChars <= 0) { xrErrno = XrINVALIDPARM; return (FALSE); } else if ((teInfoPtr->label) && strlen(teInfoPtr->label) && (teInfoPtr->labelPosition != XrLEFT_ALIGNED) && (teInfoPtr->labelPosition != XrRIGHT_ALIGNED)) { xrErrno = XrINVALIDOPTION; return (FALSE); } } /* Make sure the specified rectangle is not too small */ if (sizeTextEdit (teInfoPtr, &workRect) == FALSE) return (FALSE); editorRect = &teInfoPtr->editorRect; if ((editorRect->width < workRect.width) || (editorRect->height != workRect.height)) { xrErrno = XrINVALIDRECT; return (FALSE); } /* Get the font description */ fontPtr = (teInfoPtr->editorFont) ? teInfoPtr->editorFont : xrBaseFontInfo; _XrTextInfo (fontPtr, &teDataPtr->teFont); /* Get the size of the block cursor */ teDataPtr->teSpaceWidth = XrStringWidth (fontPtr, " ", 1, 0, 0); /* Determine the character cell width to use */ if (teInfoPtr->cellWidth == XrMAXWIDTH) teDataPtr->teCellWidth = teDataPtr->teFont.maxWidth; else if (teInfoPtr->cellWidth == XrAVGWIDTH) teDataPtr->teCellWidth = teDataPtr->teFont.avgWidth; else teDataPtr->teCellWidth = teInfoPtr->cellWidth; /* * Determine the size of the text editing region, including space * for the block cursor at the end. */ maxTextWidth = (teInfoPtr->maxChars * teDataPtr->teCellWidth) + teDataPtr->teSpaceWidth + 1; /* * Determine the base line to be used when displaying both the label * and the text string. It is calculated as follows: * * baseLine = top of editor rectangle + border height + padding */ textBaseLine = editorRect->y + BORDER + teDataPtr->teFont.leading; /* * Set the starting point for the label string. * It is calculated as follows: * * if (left aligned) * x = left edge of editor rectangle * else * x = right edge of editor rectangle - label width * y = textBaseLine. */ if (teInfoPtr->labelPosition == XrLEFT_ALIGNED) x = editorRect->x; else { x = (editorRect->x + editorRect->width - 1) - XrStringWidth (fontPtr, teInfoPtr->label, XrNULLTERMINATED, 0, 0); } XrSetPt (&teDataPtr->teLabelPt, x, textBaseLine); /* * Determine the size and location of the text region frame: * It is calculate as follows: * * if (left aligned) * x = right edge of editor rectangle - border width - * padding - width of the text region - padding - border * else * x = left edge of the editor rectangle * y = top of the editor rectangle * width = border width + padding + width of the text region + * padding + border width * height = height of the editor rectangle */ if (teInfoPtr->labelPosition == XrLEFT_ALIGNED) x = (editorRect->x+editorRect->width-1) - (BORDER << 1) - (PADDING << 1) - maxTextWidth; else x = editorRect->x; width = maxTextWidth + (BORDER << 1) + (PADDING << 1); XrSetRect (&teDataPtr->teFrameRect, x, editorRect->y, width, editorRect->height); /* * Set the starting point for the editable text string. * It is calculated as follows: * * x = left edge of frame rectangle + border width + padding * y = textBaseLine */ XrSetPt (&teDataPtr->teTextPt, teDataPtr->teFrameRect.x + BORDER + PADDING, textBaseLine); if (message == MSG_NEW) { teDataPtr->teFGColor = (teInfoPtr->editorFGColor == -1) ? xrForegroundColor : teInfoPtr->editorFGColor; teDataPtr->teBGColor = (teInfoPtr->editorBGColor == -1) ? xrBackgroundColor : teInfoPtr->editorBGColor; /* Create the 50% tile used when drawing insensitive text editor */ if ((teInfoPtr->editorFGColor == -1) && (teInfoPtr->editorBGColor == -1)) { /* Use the default 50% tile */ teDataPtr->teTileId = xrDefaultTile; } else { bitmapInfo.resourceType = XrTYPE_BITMAPID; bitmapInfo.resourceId = XrPERCENT50; if ((XrResource (MSG_FIND, &bitmapInfo) == FALSE) || ((teDataPtr->teTileId = XMakePixmap (((xrBitmapId *)bitmapInfo.resourceObject)->bitmapId, teDataPtr->teFGColor, teDataPtr->teBGColor)) == 0)) { /* Unable to create the tile */ xrErrno = XrXCALLFAILED; return (FALSE); } } /* Fill in the rest of the fields in the text edit structures */ teDataPtr->teLabel = teInfoPtr->label; teDataPtr->teString = teInfoPtr->string; teDataPtr->teMaxChars = teInfoPtr->maxChars; teDataPtr->teInsertPos = teInfoPtr->insertPos; teDataPtr->teCursorOn = FALSE; teDataPtr->teLabelPosition = teInfoPtr->labelPosition; teDataPtr->teInsertMode = teInfoPtr->insertMode; teDataPtr->teInsertState = FALSE; } return (TRUE); } \f /*************************************<->************************************* * * INT32 * drawTextEdit (textEdit, components) * * xrEditor * textEdit; * INT32 components; * * Description: * ----------- * This routine will draw either all or just a portion of an existing * text edit instance. It is capable of making the complete instance * invisible, or drawing the complete instance, or drawing just the * editing string. * * * Inputs: * ------ * textEdit = This is the instance pointer for the instance which * is to be drawn. * * components = This specifies which pieces of the instance are to * be drawn. If set to XrINITANDDRAWALL, then the * required graphic context structure will first be * initialized, and then the complete instance will be * drawn. If set to XrALLCOMPONENTS, then it will be * assumed that the graphic contexts have already been * set, and the complete instance will be drawn. If * set to XrSTRINGONLY, then it will be assumed that the * graphic contexts have already been set, and only the * editing string will be drawn. * * Outputs: * ------- * * Procedures Called * ----------------- * _XrMakeInvisible() [editorUtil.c] * _XrImageText8() [textUtil.c] * XrBorderFillRectangle() [rectUtil.c] * XrFillRectangle() [rectUtil.c] * XrInsetRect() [calc.c] * XrCopyRect() [calc.c] * drawCursor() * teInitGCs() * *************************************<->***********************************/ static INT32 drawTextEdit (textEdit, components) xrEditor * textEdit; INT32 components; { register xrTextEditData * teDataPtr; Window windowId; INT32 sensitive; RECTANGLE frameRect; RECTANGLE workRect; INT32 borderGC; INT16 delta; INT16 oldFrameX; INT32 stringLen; register INT32 visibleChars; INT16 rightEdge; FontInfo * fontPtr; /* Initialize variables */ teDataPtr = (xrTextEditData *) textEdit->editorData; windowId = textEdit->editorWindowId; /* * If the instance is not visible, then fill its area with the * background tile for the window, thus making the instance invisible. */ if (!(textEdit->editorState & XrVISIBLE)) { _XrMakeInvisible (windowId, &textEdit->editorRect, TRUE); return; } if (components == XrINITANDDRAWALL) { /* Initialize the graphic contexts */ teInitGCs (teDataPtr); components = XrALLCOMPONENTS; } sensitive = (textEdit->editorState & XrSENSITIVE) ? TRUE : FALSE; XrCopyRect (&teDataPtr->teFrameRect, &frameRect); /* Determine which components of the instance are to be drawn */ if (components == XrALLCOMPONENTS) { /* Display the label */ if (teDataPtr->teLabel) _XrImageText8 (windowId, xrEditorGC1, XrNULLTERMINATED, teDataPtr->teLabelPt.x, teDataPtr->teLabelPt.y, teDataPtr->teLabel); /* * Adjust the definition of the frame rectangle, to take into * account the border width. */ if (teDataPtr->teCursorOn) { frameRect.width -= BORDER; frameRect.height -= BORDER; borderGC = xrEditorGC3; } else { _XrMakeInvisible (windowId, &frameRect, TRUE); XrInsetRect (&frameRect, BORDER, BORDER); borderGC = xrEditorGC1; } /* Draw the text edit region and frame */ if (textEdit->editorState & XrSENSITIVE) _XrBorderFillRectangle (windowId, borderGC, xrEditorGC2, &frameRect); else _XrBorderFillRectangle (windowId, borderGC, xrEditorGC3, &frameRect); } if (components & XrSTRINGONLY) { /* If the text string is too long, then truncate it */ stringLen = strlen (teDataPtr->teString); if (stringLen > teDataPtr->teMaxChars) { teDataPtr->teString[teDataPtr->teMaxChars] = NULL; stringLen = teDataPtr->teMaxChars; } if (teDataPtr->teInsertPos > stringLen) teDataPtr->teInsertPos = stringLen; /* Determine how many character can be displayed */ visibleChars = stringLen; rightEdge = teDataPtr->teFrameRect.x + teDataPtr->teFrameRect.width - (BORDER + PADDING); fontPtr = teDataPtr->teFont.fontInfo; while ((teDataPtr->teTextPt.x + XrStringWidth (fontPtr, teDataPtr->teString, visibleChars, 0, 0)) > rightEdge) { visibleChars--; } /* Display the text string */ if (sensitive) _XrImageText8 (windowId, xrEditorGC1, visibleChars, teDataPtr->teTextPt.x, teDataPtr->teTextPt.y, teDataPtr->teString); else { /* Display as patterned out text string */ _XrImageText8 (windowId, xrEditorGC4, visibleChars, teDataPtr->teTextPt.x, teDataPtr->teTextPt.y, teDataPtr->teString); _XrImageText8 (windowId, xrEditorGC5, visibleChars, teDataPtr->teTextPt.x, teDataPtr->teTextPt.y, teDataPtr->teString); } /* Blank out past the end of the text string */ if (components == XrSTRINGONLY) { XrInsetRect (&frameRect, (BORDER -1) << 1, (BORDER -1) << 1); delta = XrStringWidth (fontPtr,teDataPtr->teString,visibleChars,0,0); oldFrameX = frameRect.x; frameRect.x = teDataPtr->teTextPt.x + delta; frameRect.width -= (frameRect.x - oldFrameX); /* Don't overwrite the cursor, if at end of the field */ if ((teDataPtr->teInsertPos == stringLen) && (teDataPtr->teInsertPos < visibleChars)) { if ((teDataPtr->teInsertMode == XrALWAYS_ON) || ((teDataPtr->teInsertMode == XrINTERACTIVE) && (teDataPtr->teInsertState))) { /* Currently using the insert mode cursor */ } else { frameRect.x += teDataPtr->teSpaceWidth; frameRect.width -= teDataPtr->teSpaceWidth; } } if (sensitive) _XrFillRectangle (windowId, xrEditorGC2, &frameRect); else _XrFillRectangle (windowId, xrEditorGC3, &frameRect); } if (teDataPtr->teCursorOn) { /* Display the text cursor */ drawCursor (windowId, textEdit, TRUE); } } } \f /*************************************<->************************************* * * xrEditor * * processTextEdit (textEdit, eventPtr) * * Description: * ----------- * This is the main event processing routine the the text editor. * When it first receives an event, it will call the various * sub-event handlers (ascii, traversal, editing and button) * and will give them the opportunity to handle the event. If the * event is handled, then it will read the input queue, and wait * for the next event. This continues until either a permanent * exit condition occurs (a SELECT outside the instance, or a * traversal event), or a temporary break condition occurs (one * of the status events occurs, or an unknown event is received). * When the sub-event handler is called, it is passed some information * describing the new event, along with a pointer to a partially filled * out X-ray event structure; if the sub-event handler plans to exit, * it fills out the rest of the X-ray event, pushes it onto the * input queue, and returns a value of TRUE. * * * Inputs: * ------ * textEdit = This is the instance pointer for the instance to which * the input event is to be applied. * * eventPtr = This is a pointer to an XEvent structure, containing the * event to be processed. * * Outputs: * ------- * Upon exiting, if any events were handled, then TRUE is returned, * along with anywhere from 1 to 2 events pushed onto the front * of the input queue. * * If the initial event received (pointed to by 'eventPtr') is not * handled, then NULL is returned. * * Procedures Called * ----------------- * XrInput() [input.c] * teInitGCs() * teButtonEvent() * teTraversalEvent() * teAsciiEvent() * teEditEvent() * *************************************<->***********************************/ static xrEditor * processTextEdit (textEdit, eventPtr) register xrEditor * textEdit; register XEvent * eventPtr; { register xrTextEditData * teDataPtr; xrEvent teEvent; INT8 exitFlag; UINT16 code; INT8 * string; INT32 byteCount; teDataPtr = (xrTextEditData *) textEdit->editorData; /* Initialize the return event structure */ teEvent.type = XrXRAY; teEvent.source = eventPtr->window; teEvent.inputType = XrEDITOR; teEvent.inputCode = XrTEXTEDIT; teEvent.valuePtr = (INT32) textEdit; teInitGCs (teDataPtr); /* Keep processing until a terminating event occurs */ while (1) { exitFlag = FALSE; if ((eventPtr->type == ButtonPressed) || (eventPtr->type == ButtonReleased)) { teButtonEvent (textEdit, teDataPtr, eventPtr, &teEvent, &exitFlag); if (exitFlag) return (textEdit); } else if (eventPtr->type == KeyPressed) { string = XrInputMap (eventPtr, &byteCount); if (byteCount == 1) code = *string & 0xFF; else if (byteCount == 2) code = (*string << 8) + *(string + 1); if (byteCount == 1 || byteCount == 2) { if (teTraversalEvent (textEdit, teDataPtr, code, &teEvent)) { return (textEdit); } else if (teAsciiEvent (textEdit, teDataPtr, code, eventPtr, &teEvent, &exitFlag)) { if (exitFlag) return (textEdit); } else if (teEditEvent (textEdit,teDataPtr,code,&teEvent,&exitFlag)) { if (exitFlag) return (textEdit); } } } else if (eventPtr->type == KeyReleased) { /* Swallow all of these events */ } else { if (teDataPtr->teCursorOn) { /* * Unknown Event: * Push the unknown event onto the input queue, along with * a text edit event, and return to the application. */ XrInput (NULL, MSG_PUSHEVENT, eventPtr); teEvent.value1 = XrUNKNOWN_EVENT; XrInput (NULL, MSG_PUSHEVENT, &teEvent); return (textEdit); } else return ((xrEditor *) NULL); } /* Grab the next input event */ while (1) { if ((XrInput (NULL, MSG_BLKREAD, eventPtr) != FALSE) && (eventPtr->window == textEdit->editorWindowId)) break; } } /* End of while loop */ } \f /*************************************<->************************************* * * INT32 * teButtonEvent (textEdit, teDataPtr, event, returnEvent, exitFlag) * * xrEditor * textEdit; * xrTextEditData * teDataPtr; * XButonEvent * event; * xrEvent * returnEvent; * INT8 exitFlag; * * Description: * ----------- * This routine takes the 'event', and first determines if it is a * button event; if not, it returns and does nothing. If it is, then * it checks to see if it is a SELECT or SELECTUP event; if not, then * it is treated as an unknown event, and both the event and an * X-ray 'unknown' event will be pushed onto the input queue, and the * application will be given the change to handle it. The SELECTUP * will be swallowed. If this is a SELECT event, then a check will be * made to see if it occurred within the instance. If it did, then the * cursor will be moved to the character cell nearest to where the * select occurred. If the select is outside the instance, then the * select event will be pushed back onto the input queue, along with * another event indicating that the instance is going inactive, and * the instance will then be drawn as inactive; the application is * then given the opportunity to handle the select event. * * * Inputs: * ------ * textEdit = This is the instance pointer for the text edit instance * to which the event is to be applied. * * teDataPtr = This is a pointer to the 'data' structure associated * with the instance. * * event = This is a pointer to the X event to be processed. * * returnEvent = This is a pointer to a partially filled out X-ray * event structure. If we need to push an X-ray event * onto the front of the input queue, we simply fill * out any additional fields necessary, and then use * this. * * exitFlag = This allows us to signal to the main event handler that * the event just handled is causing us to exit and return * to the application; this is set when either an unknown * event is received, or a select outside the instance * occurs. * * Outputs: * ------- * Upon completion, 'exitFlag' will be set as described above, and * it is possible that 1 or more events have been pushed onto * the front of the input queue. * * Procedures Called * ----------------- * XrMapButton() [utilities.c] * XrSetPt() [calc.c] * XrInput() [input.c] * XrStringWidth() [utilities.c] * XFlush() [libX.a] * drawCursor() * drawTextEdit() * *************************************<->***********************************/ static INT32 teButtonEvent (textEdit, teDataPtr, event, returnEvent, exitFlag) xrEditor * textEdit; xrTextEditData * teDataPtr; XButtonEvent * event; xrEvent * returnEvent; INT8 * exitFlag; { register INT32 i; POINT cursorPos; INT16 stringWidth; if (XrMapButton (XrSELECT, event)) { /* If the select is outside the editor's rectangle, then break */ XrSetPt (&cursorPos, event->x, event->y); if (!XrPtInRect (&cursorPos, &textEdit->editorRect)) { /* * Return two events: the select which is causing us to * exit, followed by the break notification. */ XrInput (NULL, MSG_PUSHEVENT, event); returnEvent->value1 = XrTEDIT_BREAK; returnEvent->value2 = XrSELECT; XrInput (NULL, MSG_PUSHEVENT, returnEvent); /* Redraw the field as inactive */ teDataPtr->teCursorOn = FALSE; drawTextEdit (textEdit, XrALLCOMPONENTS); XFlush(); *exitFlag = TRUE; return; } /* Determine where to place the insertion bar */ for (i = 1; i <= strlen(teDataPtr->teString); i++) { stringWidth = XrStringWidth (teDataPtr->teFont.fontInfo, teDataPtr->teString, i, 0, 0); if (cursorPos.x < teDataPtr->teTextPt.x + stringWidth) break; } /* * Update the insertion bar location, force the field * active, and redraw the instance. */ if (!teDataPtr->teCursorOn) { teDataPtr->teInsertPos = i - 1; teDataPtr->teCursorOn = TRUE; drawTextEdit (textEdit, XrALLCOMPONENTS); } else { /* Just move the cursor */ drawCursor (textEdit->editorWindowId, textEdit, FALSE); teDataPtr->teInsertPos = i - 1; drawCursor (textEdit->editorWindowId, textEdit, TRUE); } return; } else if (XrMapButton (XrSELECTUP, event)) { /* Swallow a selectup event */ return; } else { /* * Treat all other events as unknown events. * Push it back on the input queue, and add * a text edit break event afterwards. */ XrInput (NULL, MSG_PUSHEVENT, event); returnEvent->value1 = XrUNKNOWN_EVENT; XrInput (NULL, MSG_PUSHEVENT, returnEvent); *exitFlag = TRUE; return; } } \f /*************************************<->************************************* * * INT32 * teAsciiEvent (textEdit, teDataPtr, keyCode, eventPtr, returnEvent, exitFlag) * * xrEditor * textEdit; * xrTextEditData * teDataPtr; * UINT16 keyCode; * XButtonEvent * eventPtr; * xrEvent * returnEvent; * INT8 exitFlag; * * Description: * ----------- * This routine takes the keycode, and first determines if it maps to * an ascii key; if not, it returns without doing anything. If it * is, and if it is printable then the character is added to the * editing string, and the cursor is updated; if the field is full, * or if the character is unprintable, then it is swallowed. If this * is the first character in the field, then a 'first character' * status event will be pushed onto the input queue, and we will * signal to the main handler that we need to return to the application. * * * Inputs: * ------ * textEdit = This is the instance pointer for the text edit instance * to which the event is to be applied. * * teDataPtr = This is a pointer to the 'data' structure associated * with the instance. * * keyCode = This contains the keyCode into which the event mapped. * * eventPtr = Pointer to the event containing the keyCode value. * * returnEvent = This is a pointer to a partially filled out X-ray * event structure. If we need to push an X-ray event * onto the front of the input queue, we simply fill * out any additional fields necessary, and then use * this. * * exitFlag = This allows us to signal to the main event handler that * the event just handled is causing us to exit and return * to the application; this is set only upon receipt of * the first character in the editing field. * * Outputs: * ------- * If the keyCode is handled by this routine, then TRUE will be returned, * and 'exitFlag' will be set as described above. In addition, a * single status event may be pushed onto the input queue. * * If the keyCode is not handled here, then FALSE is returned. * * Procedures Called * ----------------- * XLookupMapping() [libX.a] * XrInput() [input.c] * drawTextEdit() * *************************************<->***********************************/ static INT32 teAsciiEvent (textEdit, teDataPtr, keyCode, eventPtr, returnEvent, exitFlag) xrEditor * textEdit; register xrTextEditData * teDataPtr; UINT16 keyCode; XButtonEvent * eventPtr; xrEvent * returnEvent; INT8 * exitFlag; { Window windowId; UINT8 key; register INT32 cursorPos; INT32 stringLen; INT8 cursorOn; register INT32 i; /* Test to see if this is a regular ascii event */ cursorPos = teDataPtr->teInsertPos; stringLen = strlen (teDataPtr->teString); cursorOn = teDataPtr->teCursorOn; windowId = textEdit->editorWindowId; /* Exit, if event is not an ascii key event */ if (((keyCode & 0xFF00) == K_s) || (keyCode == '\010') || (keyCode == '\177') || (keyCode == '\377')) return (FALSE); /* See if the key falls within the printable range */ key = keyCode & 0xFF; if (key >= '\040') { if ((teDataPtr->teInsertMode == XrALWAYS_ON) || ((teDataPtr->teInsertMode == XrINTERACTIVE) && (teDataPtr->teInsertState))) { /* * Currently operating in insert mode. * See if the field is already full. */ if ((cursorPos < teDataPtr->teMaxChars) && (stringLen < teDataPtr->teMaxChars)) { /* Shift characters to the right */ for (i = stringLen + 1; i > cursorPos; i--) teDataPtr->teString[i] = teDataPtr->teString[i-1]; teDataPtr->teString[cursorPos] = key; if (strlen(teDataPtr->teString) == 1) { returnEvent->value1 = XrTEDIT_FIRST; XrInput (NULL, MSG_PUSHEVENT, returnEvent); *exitFlag = TRUE; } /* Remove the old cursor */ if (cursorOn) drawCursor (windowId, textEdit, FALSE); teDataPtr->teInsertPos++; } /* Field is already full */ else if (cursorOn) return (TRUE); } else { /* * Currently operating in normal character insertion mode. * Add the character only if the field is not full. */ if (cursorPos < teDataPtr->teMaxChars) { if (cursorPos == stringLen) teDataPtr->teString[cursorPos+1] = '\0'; teDataPtr->teString[cursorPos] = key; if (strlen(teDataPtr->teString) == 1) { returnEvent->value1 = XrTEDIT_FIRST; XrInput (NULL, MSG_PUSHEVENT, returnEvent); *exitFlag = TRUE; } /* Remove the old cursor */ if (cursorOn) drawCursor (windowId, textEdit, FALSE); teDataPtr->teInsertPos++; } /* Field is already full */ else if (cursorOn) return (TRUE); } } else { /* Treat control characters as Unknown events */ XrInput (NULL, MSG_PUSHEVENT, eventPtr); returnEvent->value1 = XrUNKNOWN_EVENT; XrInput (NULL, MSG_PUSHEVENT, returnEvent); *exitFlag = TRUE; if (cursorOn) return (TRUE); } /* Activate the field, if necessary, and redraw it */ if (teDataPtr->teCursorOn == FALSE) { teDataPtr->teCursorOn = TRUE; drawTextEdit (textEdit, XrALLCOMPONENTS); } else drawTextEdit (textEdit, XrSTRINGONLY); return (TRUE); } \f /*************************************<->************************************* * * INT32 * teEditEvent (textEdit, teDataPtr, keyCode, returnEvent, exitFlag) * * xrEditor * textEdit; * xrTextEditData * teDataPtr; * UINT16 keyCode; * xrEvent * returnEvent; * INT8 exitFlag; * * Description: * ----------- * This routine is responsible for handling all of the editing keys. * These are composed of the 'cursor right', 'cursor left', 'backspace', * 'delete char', 'delete line', 'clear line' and 'insert char' keys. * * * Inputs: * ------ * textEdit = This is the instance pointer for the text edit instance * to which the event is to be applied. * * teDataPtr = This is a pointer to the 'data' structure associated * with the instance. * * keyCode = This is the keycode into which the event mapped. * * returnEvent = This is a pointer to a partially filled out X-ray * event structure. If we need to push an X-ray event * onto the front of the input queue, we simply fill * out any additional fields necessary, and then use * this. * * exitFlag = This allows us to signal to the main event handler that * the event just handled is causing us to exit and return * to the application; this is set only when the event * causes the editing field to become empty. * * Outputs: * ------- * If the event is handled, then TRUE is returned, else FALSE. * * Procedures Called * ----------------- * XrInput() [input.c] * drawTextEdit() * drawCursor() * *************************************<->***********************************/ static INT32 teEditEvent (textEdit, teDataPtr, keyCode, returnEvent, exitFlag) xrEditor * textEdit; register xrTextEditData * teDataPtr; UINT16 keyCode; xrEvent * returnEvent; INT8 * exitFlag; { register INT32 cursorPos; INT32 stringLen; INT8 cursorOn; Window windowId; stringLen = strlen (teDataPtr->teString); cursorPos = teDataPtr->teInsertPos; cursorOn = teDataPtr->teCursorOn; windowId = textEdit->editorWindowId; if (keyCode == (CURS_RT_KEY | K_s)) { /* * If not at the end of the string, then move the * cursor right one character position. */ if (cursorPos < stringLen) { if (cursorOn) { drawCursor (windowId, textEdit, FALSE); teDataPtr->teInsertPos++; drawCursor (windowId, textEdit, TRUE); return (TRUE); } else teDataPtr->teInsertPos++; } else if (cursorOn) return (TRUE); } else if (keyCode == (CURS_LF_KEY | K_s)) { /* * If not at the start of the string, then move * the cursor left one character position. */ if (cursorPos > 0) { if (cursorOn) { drawCursor (windowId, textEdit, FALSE); teDataPtr->teInsertPos--; drawCursor (windowId, textEdit, TRUE); return (TRUE); } else teDataPtr->teInsertPos--; } else if (cursorOn) return (TRUE); } else if ((keyCode == (BS_KEY | K_s)) || (keyCode == '\010') || (keyCode == '\177') || (keyCode == '\377')) { /* * If not at the start of the string, then delete the * character to the left of the cursor. */ if (cursorPos > 0) { strcpy (teDataPtr->teString+cursorPos-1,teDataPtr->teString+cursorPos); teDataPtr->teInsertPos--; if (strlen (teDataPtr->teString) == 0) { returnEvent->value1 = XrTEDIT_EMPTY; XrInput (NULL, MSG_PUSHEVENT, returnEvent); *exitFlag = TRUE; } } else if (cursorOn) return (TRUE); } else if (keyCode == (DEL_CHAR_KEY | K_s)) { /* * If not at the end of the string, then delete * the character under the cursor. */ if (cursorPos < stringLen) { strcpy (teDataPtr->teString+cursorPos,teDataPtr->teString+cursorPos+1); if (strlen (teDataPtr->teString) == 0) { returnEvent->value1 = XrTEDIT_EMPTY; XrInput (NULL, MSG_PUSHEVENT, returnEvent); *exitFlag = TRUE; } } else if (cursorOn) return (TRUE); } else if (keyCode == (DEL_LINE_KEY | K_s)) { /* Clear out the whole line */ teDataPtr->teInsertPos = 0; teDataPtr->teString[0] = '\0'; returnEvent->value1 = XrTEDIT_EMPTY; XrInput (NULL, MSG_PUSHEVENT, returnEvent); *exitFlag = TRUE; } else if (keyCode == (CLR_LINE_KEY | K_s)) { /* Clear from the cursor to the end */ teDataPtr->teString[cursorPos] = '\0'; if (cursorPos == 0) { returnEvent->value1 = XrTEDIT_EMPTY; XrInput (NULL, MSG_PUSHEVENT, returnEvent); *exitFlag = TRUE; } } else if (keyCode == (INSERT_CHAR_KEY | K_s)) { /* * Toggle into and out of insert mode, redrawing * the cursor to match the mode. */ if (teDataPtr->teInsertMode == XrINTERACTIVE) { drawCursor (windowId, textEdit, FALSE); teDataPtr->teInsertState = teDataPtr->teInsertState ? FALSE : TRUE; drawCursor (windowId, textEdit, TRUE); } return (TRUE); } else /* Not an editing key */ return (FALSE); /* Force the field active, and redraw it */ if (!teDataPtr->teCursorOn) { teDataPtr->teCursorOn = TRUE; drawTextEdit (textEdit, XrALLCOMPONENTS); } else drawTextEdit (textEdit, XrSTRINGONLY); return (TRUE); } \f /*************************************<->************************************* * * teTraversalEvent (textEdit, teDataPtr, keyCode, returnEvent) * * xrEditor * textEdit; * xrTextEditData * teDataPtr; * UINT16 keyCode; * xrEvent * returnEvent; * * Description: * ----------- * This routine handles the 3 traversal keys: tab, backtab and return. * When a traversal event occurs, the field will be drawn as inactive, * and a traversal event will be pushed onto the front of the input * queue; this is a permanent break condition. * * * Inputs: * ------ * textEdit = This is the instance pointer for the text edit instance * to which the event is to be applied. * * teDataPtr = This is a pointer to the 'data' structure associated * with the instance. * * keyCode = This is the keyCode into which the event mapped. * * returnEvent = This is a pointer to a partially filled out X-ray * event structure. If we need to push an X-ray event * onto the front of the input queue, we simply fill * out any additional fields necessary, and then use * this. * * Outputs: * ------- * If the event was a traversal key, then TRUE is returned, and a * break event is added to the front of the input queue. * * If this is not a traversal key, then FALSE is returned. * * Procedures Called * ----------------- * XFlush() [libX.a] * XrInput() [input.c] * drawTextEdit() * *************************************<->***********************************/ static INT32 teTraversalEvent (textEdit, teDataPtr, keyCode, returnEvent) xrEditor * textEdit; xrTextEditData * teDataPtr; register UINT16 keyCode; xrEvent * returnEvent; { /* * Check for a forward or backward traversal request. */ if ((keyCode == '\r') || (keyCode == '\n')) keyCode = RETURN_KEY | K_s; else if (keyCode == '\t') keyCode = TAB_KEY | K_s; if ((keyCode == (RETURN_KEY | K_s)) || (keyCode == (TAB_KEY | K_s))) { /* Traverse forward; turn off this field */ teDataPtr->teCursorOn = FALSE; drawTextEdit (textEdit, XrALLCOMPONENTS); XFlush(); returnEvent->value1 = XrTEDIT_BREAK; returnEvent->value2 = XrNEXT; returnEvent->value3 = keyCode; XrInput (NULL, MSG_PUSHEVENT, returnEvent); return (TRUE); } else if (keyCode == (BACKTAB_KEY | K_s)) { /* Traverse backward; turn off this field */ teDataPtr->teCursorOn = FALSE; drawTextEdit (textEdit, XrALLCOMPONENTS); XFlush(); returnEvent->value1 = XrTEDIT_BREAK; returnEvent->value2 = XrPREVIOUS; returnEvent->value3 = keyCode; XrInput (NULL, MSG_PUSHEVENT, returnEvent); return (TRUE); } /* Else this is not a traversal key */ return (FALSE); } \f /*************************************<->************************************* * * drawCursor (windowId, textEdit, showing) * * Window windowId; * xrEditor * textEdit; * INT8 showing; * * Description: * ----------- * This routine turns the text cursor on and off, depending upon * whether the 'showing' parameter is set to TRUE or FALSE. The * insert mode cursor is drawn as a 1 pixel wide vertical bar, * while the normal mode cursor is drawn as a block. If the * cursor is currently outside the editing field, then no drawing * occurs. * * * Inputs: * ------ * windowId = This is the window Id for the window in which the text * edit instance resides. * * textEdit = This is the editor instance pointer. * * showing = If the cursor is to be turned on, then this should be * set to TRUE; the cursor is turned off when this is set * to FALSE. * * Outputs: * ------- * * Procedures Called * ----------------- * XrStringWidth() [utilities.c] * _XrLine() [rectUtil.c] * _XrImageText8() [textUtil.c] * *************************************<->***********************************/ static drawCursor (windowId, textEdit, showing) Window windowId; xrEditor * textEdit; INT8 showing; { register xrTextEditData * teDataPtr; register xrTextInfo * fontPtr; INT8 useBlankCursor = FALSE; INT8 cursorChar; register INT16 cursorX; register INT16 cursorY; teDataPtr = (xrTextEditData *) textEdit->editorData; fontPtr = &teDataPtr->teFont; /* Don't bother drawing if we're insensitive */ if (! (textEdit->editorState & XrSENSITIVE)) return; /* * Check for invalid cursor position, and also see if * the cursor is at the end of the text field; this lets * us know if we need to use a space character as the block * cursor. */ if (teDataPtr->teInsertPos >= teDataPtr->teMaxChars) { teDataPtr->teInsertPos = teDataPtr->teMaxChars; useBlankCursor = TRUE; } else if (teDataPtr->teInsertPos >= strlen(teDataPtr->teString)) useBlankCursor = TRUE; /* Determine the x position for the cursor */ cursorX = teDataPtr->teTextPt.x + XrStringWidth (fontPtr->fontInfo, teDataPtr->teString, teDataPtr->teInsertPos, 0, 0); if ((teDataPtr->teInsertMode == XrALWAYS_ON) || ((teDataPtr->teInsertMode == XrINTERACTIVE) && teDataPtr->teInsertState)) { /* Currently operating in insert mode */ cursorX -= 1; cursorY = teDataPtr->teFrameRect.y + BORDER + fontPtr->leading; /* Don't draw the cursor if it's outside the editing region */ if (cursorX + 1 > (teDataPtr->teFrameRect.x + teDataPtr->teFrameRect.width - 5)) return; if (showing) _XrLine (windowId, xrEditorGC1, cursorX, cursorY, cursorX, cursorY + (fontPtr->ascent + fontPtr->descent - 1)); else _XrLine (windowId, xrEditorGC2, cursorX, cursorY, cursorX, cursorY + (fontPtr->ascent + fontPtr->descent - 1)); } else { /* Currently operating in normal mode */ if (useBlankCursor) cursorChar = ' '; else cursorChar = teDataPtr->teString[teDataPtr->teInsertPos]; /* Don't draw the cursor if it's outside the editing region */ if ((cursorX + XrStringWidth (fontPtr->fontInfo, &cursorChar, 1, 0, 0)) > (teDataPtr->teFrameRect.x + teDataPtr->teFrameRect.width-5)) return; if (showing) { _XrImageText8 (windowId, xrEditorGC2, 1, cursorX, teDataPtr->teTextPt.y, &cursorChar); _XrLine (windowId, xrEditorGC1, cursorX - 1, teDataPtr->teTextPt.y, cursorX - 1, teDataPtr->teTextPt.y + fontPtr->ascent + fontPtr->descent - 1); } else { _XrImageText8 (windowId, xrEditorGC1, 1, cursorX, teDataPtr->teTextPt.y, &cursorChar); _XrLine (windowId, xrEditorGC2, cursorX - 1, teDataPtr->teTextPt.y, cursorX - 1, teDataPtr->teTextPt.y + fontPtr->ascent + fontPtr->descent - 1); } } } \f /*************************************<->************************************* * * xrEditor * * teActivate (textEdit) * * xrEditor * textEdit; * * Description: * ----------- * This is the handler for the MSG_ACTIVATE message. It will allow * an existing text edit field to be activated, only if the instance * is both visible and sensitive. After verify the parameters and * the instance's state, the instance will be redrawn as active, and * then this routine will wait for an input event to be received. * When an event is received, the main event handler will be called, * and passed the event; it will then maintain control until an * exit condition occurs. * * * Inputs: * ------ * textEdit = This is the instance pointer for the text edit instance * which is to be activated. * * Outputs: * ------- * If the field is successfully activated, then the instance pointer * will be returned; otherwise, NULL will be returned. * * Procedures Called * ----------------- * XrInput() [input.c] * drawTextEdit() * processTextEdit() * *************************************<->***********************************/ static xrEditor * teActivate (textEdit) register xrEditor * textEdit; { xrTextEditData * teDataPtr; XEvent event; /* Validate the instance pointer */ if (textEdit == NULL) { xrErrno = XrINVALIDID; return ((xrEditor *) NULL); } /* Fail, if the instance is not visible and sensitive */ if ((textEdit->editorState & (XrVISIBLE | XrSENSITIVE)) != (XrVISIBLE | XrSENSITIVE)) { xrErrno = XrINVALIDPARM; return ((xrEditor *) NULL); } teDataPtr = (xrTextEditData *) textEdit->editorData; /* Activate the field, if not already */ if (! (teDataPtr->teCursorOn)) { teDataPtr->teCursorOn = TRUE; drawTextEdit (textEdit, XrINITANDDRAWALL); } else { teInitGCs (teDataPtr); drawTextEdit (textEdit, XrSTRINGONLY); } /* Wait for the initial input event */ while (1) { if ((XrInput (NULL, MSG_BLKREAD, &event) != FALSE) && (event.window == textEdit->editorWindowId)) break; } /* Let the processing routine take it from here */ return (processTextEdit (textEdit, &event)); } \f /*************************************<->************************************* * * xrEditor * * teMOVE_handler (textEdit, ptPtr) * * xrEditor * textEdit; * POINT * ptPtr; * * Description: * ----------- * This is the handler for the MSG_MOVE message. It takes a new * origin point, and offsets each component within the instance, * such that the instance is now positioned with the upper left * corner of the editor rectangle at the specified point. In * addition, the editor group manager is invoked, to recalculate * the editor group rectangle for the group in which this instance * is a member. * * * Inputs: * ------ * textEdit = This is the instance pointer for the instance to be moved. * * ptPtr = This points to a POINT structure, containing the new origin. * * Outputs: * ------- * Upon successful completion, the instance pointer is returned, * and the instance will be moved; it is redrawn only if it * is visible. * * Upon failure, NULL is returned, and xrErrno is set. * * Procedures Called * ----------------- * XrCopyRect() [calc.c] * XrOffsetRect() [calc.c] * XrOffsetPt() [calc.c] * _XrMakeInvisible() [editorUtil.c] * XrEditorGroup() [group.c] * drawTextEdit() * *************************************<->***********************************/ static xrEditor * teMOVE_handler (textEdit, ptPtr) register xrEditor * textEdit; POINT * ptPtr; { register xrTextEditData * teDataPtr; RECTANGLE workRect; register INT16 xDelta; register INT16 yDelta; /* Check for invalid pointers */ if (textEdit == NULL) { xrErrno = XrINVALIDID; return ((xrEditor *) NULL); } else if (ptPtr == NULL) { xrErrno = XrINVALIDPTR; return ((xrEditor *) NULL); } /* Determine how much to relocate the instance by */ teDataPtr = (xrTextEditData *) textEdit->editorData; XrCopyRect (&textEdit->editorRect, &workRect); xDelta = ptPtr->x - workRect.x; yDelta = ptPtr->y - workRect.y; /* * Relocate the following components: * - the editor rectangle * - the text frame rectangle * - the label origin * - the text string origin */ XrOffsetRect (&textEdit->editorRect, xDelta, yDelta); XrOffsetRect (&teDataPtr->teFrameRect, xDelta, yDelta); XrOffsetPt (&teDataPtr->teLabelPt, xDelta, yDelta); XrOffsetPt (&teDataPtr->teTextPt, xDelta, yDelta); /* Redraw the instance, if visible */ if (textEdit->editorState & XrVISIBLE) { /* Remove the instance from the window */ _XrMakeInvisible (textEdit->editorWindowId, &workRect, TRUE); /* Redisplay the instance at its new location */ drawTextEdit (textEdit, XrINITANDDRAWALL); } /* Force an editor group rectangle resize */ XrEditorGroup (NULL, MSG_ADJUSTGROUPRECT, textEdit); return (textEdit); } \f /*************************************<->************************************* * * xrEditor * * teRESIZE_handler (textEdit, rectPtr) * * xrEditor * textEdit; * RECTANGLE * rectPtr; * * Description: * ----------- * This is the handler routine for the MSG_RESIZE message. It takes * a rectangle definition, and relays an existing text edit instance, * such that it now fits within the specified rectangle; all size * restrictions which applied when the instance was first created are * still enforced. The resizing is accomplished by creating a fake * 'info' structure, and then calling createTextEdit(); it will fill * in the 'data' structure with the size and position information for * the instance. Afterwards, the editor group handler will be called * and given the opportunity to recalculate the group rectangle for * the group in which this instance resides. * * * Inputs: * ------ * textEdit = This instance pointer for the instance being resized. * * rectPtr = A pointer to the new editor rectangle definition. * * Outputs: * ------- * Upon successful completion, the instance pointer is returned, and * the instance will be resized; it will be redrawn only if it * is visible. * * Upon failure, NULL is returned, and xrErrno is set. * * Procedures Called * ----------------- * XrCopyRect() [calc.c] * _XrMakeInvisible() [editorUtil.c] * XrEditorGroup() [group.c] * createTextEdit() * drawTextEdit() * *************************************<->***********************************/ static xrEditor * teRESIZE_handler (textEdit, rectPtr) register xrEditor * textEdit; RECTANGLE * rectPtr; { RECTANGLE workRect; xrTextEditInfo teInfo; register xrTextEditData * teDataPtr; register xrTextEditInfo * teInfoPtr; if (textEdit == NULL) { xrErrno = XrINVALIDID; return ((xrEditor *) NULL); } else if (rectPtr == NULL) { xrErrno = XrINVALIDPTR; return ((xrEditor *) NULL); } /* Create a pseudo Info structure */ teDataPtr = (xrTextEditData *) textEdit->editorData; XrCopyRect (&textEdit->editorRect, &workRect); teInfoPtr = &teInfo; XrCopyRect (rectPtr, &teInfoPtr->editorRect); teInfoPtr->editorFont = teDataPtr->teFont.fontInfo; teInfoPtr->label = teDataPtr->teLabel; teInfoPtr->maxChars = teDataPtr->teMaxChars; teInfoPtr->labelPosition = teDataPtr->teLabelPosition; teInfoPtr->cellWidth = teDataPtr->teCellWidth; /* Allow createTextEdit() to do the calculations */ if (createTextEdit (teDataPtr, teInfoPtr, MSG_RESIZE) == FALSE) /* Must have supplied an invalid rectangle definition */ return ((xrEditor *) NULL); /* Save the new editor rectangle */ XrCopyRect (&teInfoPtr->editorRect, &textEdit->editorRect); if (textEdit->editorState & XrVISIBLE) { /* Remove the instance from the window */ _XrMakeInvisible (textEdit->editorWindowId, &workRect, TRUE); /* Redisplay the instance */ drawTextEdit (textEdit, XrINITANDDRAWALL); } /* Force an editor group rectangle resize */ XrEditorGroup (NULL, MSG_ADJUSTGROUPRECT, textEdit); return (textEdit); } \f /*************************************<->************************************* * * xrEditor * * teREDRAW_handler (textEdit, redrawMode) * * xrEditor * textEdit; * INT32 redrawMode; * * Description: * ----------- * This is the handler routine for the MSG_REDRAW message; it is * capable of handling either an XrREDRAW_ALL or XrREDRAW_ACTIVE * request. These redraw the entire field, or just the editing * string. * * * Inputs: * ------ * textEdit = This is the instance pointer for the instance to be * redrawn. * * redrawMode = This specifies the type of redraw to perform. This * must be set to either of the values mentioned in the * description above. * * Outputs: * ------- * Upon successful completion, the instance pointer is returned, and * the instance is redrawn (if it was visible). * * Upon failure, NULL is returned, and xrErrno is set. * * Procedures Called * ----------------- * drawTextEdit() * teInitGCs() * *************************************<->***********************************/ static xrEditor * teREDRAW_handler (textEdit, redrawMode) register xrEditor * textEdit; INT32 redrawMode; { register xrTextEditData * teDataPtr; /* Validate the instance pointer and the redraw mode */ if (textEdit == NULL) { xrErrno = XrINVALIDID; return ((xrEditor *) NULL); } else if (redrawMode == XrREDRAW_ALL) { if (textEdit->editorState & XrVISIBLE) drawTextEdit (textEdit, XrINITANDDRAWALL); return (textEdit); } else if (redrawMode == XrREDRAW_ACTIVE) { teDataPtr = (xrTextEditData *) textEdit->editorData; if (textEdit->editorState & XrVISIBLE) { teInitGCs (teDataPtr); drawTextEdit (textEdit, XrSTRINGONLY); } return (textEdit); } else { xrErrno = XrINVALIDOPTION; return ((xrEditor *) NULL); } } \f /*************************************<->************************************* * * xrEditor * * teINSERTMODE_handler (textEdit, insertMode) * * xrEditor * textEdit; * INT8 insertMode; * * Description: * ----------- * This is the handler for the MSG_INSERTMODE message. It allows * an application to change the way in which an existing text edit * instance will respond to the insert mode key. Insert mode may * be forced on always, forced off always, or allowed to be * interactively modified. After the mode has been changed, the * cursor will be redrawn, if the instance was visible. * * * Inputs: * ------ * textEdit = This is the instance pointer. * * insertMode = This specifies the type of insert mode the instance * should operated under. * * Outputs: * ------- * Upon successful completion, the editor instance pointer is returned, * and the new insert mode is set. * * Upon failure, NULL is returned, and xrErrno is set. * * Procedures Called * ----------------- * drawCursor() * *************************************<->***********************************/ static xrEditor * teINSERTMODE_handler (textEdit, insertMode) xrEditor * textEdit; INT8 insertMode; { xrTextEditData * teDataPtr; if (textEdit == NULL) { xrErrno = XrINVALIDID; return ((xrEditor *) NULL); } if ((insertMode != XrALWAYS_ON) && (insertMode != XrALWAYS_OFF) && (insertMode != XrINTERACTIVE)) { xrErrno = XrINVALIDOPTION; return ((xrEditor *) NULL); } teDataPtr = (xrTextEditData *) textEdit->editorData; /* Turn off the old cursor */ if ((textEdit->editorState & XrVISIBLE) && (teDataPtr->teCursorOn)) drawCursor (textEdit->editorWindowId, textEdit, FALSE); teDataPtr->teInsertMode = insertMode; teDataPtr->teInsertState = FALSE; /* Turn on the new cursor */ if ((textEdit->editorState & XrVISIBLE) && (teDataPtr->teCursorOn)) drawCursor (textEdit->editorWindowId, textEdit, TRUE); return (textEdit); } \f /*************************************<->************************************* * * teInitGCs (teDataPtr) * * xrTextEditData * teDataPtr; * * Description: * ----------- * This routine initializes 5 graphics context structures. * These include ones used for drawing the wide border, ones used * for drawing a sensitive instance, and also ones used for drawing * the hashed text string displayed in an insensitive text edit instance. * * * Inputs: * ------ * teDataPtr = This points to the internal 'data' structure associated * with instance for which these graphic contexts are being * initialized; this structure contains the font and color * information. * * Outputs: * ------- * The graphic contexts references by the defines xrEditorGC1, * xrEditorGC2, xrEditorGC3, xrEditorGC4 and xrEditorGC5 will be set. * * Procedures Called * ----------------- * _XrCopyGC() [gcUtil.c] * _XrChangeGC() [gcUtil.c] * *************************************<->***********************************/ static teInitGCs (teDataPtr) register xrTextEditData * teDataPtr; { INT32 changeList[21]; INT32 changeMask; /* Initialize the standard graphic contexts we will be using */ _XrInitEditorGCs (teDataPtr->teFGColor, teDataPtr->teBGColor, teDataPtr->teFont.fontInfo->id); /* * Initialize the graphics context used to draw * the background for an insensitive text edit instance, * and the wide border. */ _XrCopyGC (xrDefaultGC, xrEditorGC3); changeList[XrFOREGROUNDVAL] = teDataPtr->teFGColor; changeList[XrBACKGROUNDVAL] = teDataPtr->teBGColor; changeList[XrLINEWIDTHVAL] = BORDER; changeList[XrTILEVAL] = teDataPtr->teTileId; changeList[XrFILLSTYLEVAL] = Tiled; changeMask = (XrTILE | XrFILLSTYLE | XrFOREGROUND | XrBACKGROUND | XrLINEWIDTH); _XrChangeGC (xrEditorGC3, changeMask, changeList); /* * Initialize the two graphics contexts used to draw an insensitive * editing string. */ _XrCopyGC (xrDefaultGC, xrEditorGC4); changeList[XrFOREGROUNDVAL] = 0; changeList[XrBACKGROUNDVAL] = AllPlanes; changeList[XrFONTVAL] = teDataPtr->teFont.fontInfo->id; changeList[XrALUVAL] = GXand; changeMask = (XrFOREGROUND | XrBACKGROUND | XrFONT | XrALU); _XrChangeGC (xrEditorGC4, changeMask, changeList); _XrCopyGC (xrDefaultGC, xrEditorGC5); changeList[XrFOREGROUNDVAL] = teDataPtr->teFGColor; changeList[XrBACKGROUNDVAL] = 0; changeList[XrFONTVAL] = teDataPtr->teFont.fontInfo->id; changeList[XrALUVAL] = GXor; changeMask = (XrFOREGROUND | XrBACKGROUND | XrFONT | XrALU); _XrChangeGC (xrEditorGC5, changeMask, changeList); }