|
|
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);
}