|
|
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: P T
Length: 48888 (0xbef8)
Types: TextFile
Names: »PushButton.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/PushButton.c«
/*
* $Source: /u1/Xr/src/Xrlib/Editor/RCS/PushButton.c,v $
* $Header: PushButton.c,v 1.1 86/12/17 09:01:51 swick Exp $
*/
#ifndef lint
static char *rcsid_PushButton_c = "$Header: PushButton.c,v 1.1 86/12/17 09:01:51 swick Exp $";
#endif lint
#include <Xr/xr-copyright.h>
/* $Header: PushButton.c,v 1.1 86/12/17 09:01:51 swick Exp $ */
/* Copyright 1986, Hewlett-Packard Company */
/* Copyright 1986, Massachussetts Institute of Technology */
static char rcsid[] = "$Header: PushButton.c,v 1.1 86/12/17 09:01:51 swick Exp $";
/*************************************<+>*************************************
*****************************************************************************
**
** File: PushButton.c
**
** Project: X-ray Toolbox
**
** Description:
** Source code for the X-ray PushButton field editor.
**
**
** ------------------------ MODIFICATION RECORD ------------------------
*
* $Log: PushButton.c,v $
* Revision 1.1 86/12/17 09:01:51 swick
* Initial revision
*
* Revision 7.0 86/11/13 08:23:45 08:23:45 fred ()
* Final QA Release
*
* Revision 6.0 86/11/10 15:28:49 15:28:49 fred ()
* QA #2 release
*
* Revision 5.2 86/11/07 14:20:24 14:20:24 fred ()
* Added new copyright message.
*
* Revision 5.1 86/10/30 13:26:29 13:26:29 fred ()
* Added check for numCols <= 0, and changed the button
* drawing algorithm.
*
* Revision 5.0 86/10/28 08:28:45 08:28:45 fred ()
* QA #1.1 release
*
* Revision 4.1 86/10/22 11:47:00 11:47:00 fred ()
* Filled in the procedure headers.
*
* Revision 4.0 86/10/20 12:10:41 12:10:41 fred ()
* QA #1 release
*
* Revision 3.4 86/10/16 09:14:50 09:14:50 fred ()
* Performance enhanced: added use of register variables.
*
* Revision 3.3 86/10/13 10:05:30 10:05:30 fred ()
* Added use of the default tile, if needed.
*
* Revision 3.2 86/10/09 07:44:38 07:44:38 fred ()
* Added default color check to create routine.
*
* Revision 3.1 86/10/07 16:04:13 16:04:13 fred ()
* Added check for invalid rectangle size.
*
* Revision 3.0 86/10/02 15:58:40 15:58:40 fred ()
* Alpha release set to 3.0
*
* Revision 2.4 86/09/25 13:24:36 13:24:36 fred ()
* Added the compile ifdef MVAX, for drawing real ovals.
*
* Revision 2.3 86/09/22 13:10:37 13:10:37 fred ()
* Added calls to XrEditorGroup().
*
* Revision 2.2 86/09/19 12:13:52 12:13:52 fred ()
* Changed pushbuttons so that they no longer act like checkboxes.
* They turn on with a select, and off with a select up.
*
* Revision 2.1 86/09/19 07:09:55 07:09:55 fred ()
* Added a check for XrVISIBLE before doing any drawing.
*
* Revision 2.0 86/09/16 08:05:53 08:05:53 fred ()
* Updated input processing routine to use new SELECT strategy.
*
* Revision 1.4 86/09/16 05:45:45 05:45:45 fred ()
* Modified to swallow a select up event.
*
* Revision 1.3 86/09/10 07:25:30 07:25:30 fred ()
* Changed numRows to numCols in all data structures.
*
* Revision 1.2 86/09/09 13:07:26 13:07:26 fred ()
* Changed some variables from INT32 to INT16
*
* Revision 1.1 86/09/03 13:57:08 13:57:08 fred ()
* Initial revision
*
*
*****************************************************************************
*************************************<+>*************************************/
#include <X/Xlib.h>
#include <Xr/defs.h>
#include <Xr/types.h>
#include <Xr/in_types.h>
extern INT32 pbFreeMemory();
extern INT32 createPButton();
extern INT32 drawPButton();
extern INT32 processPButton();
extern INT32 calcButtonComponents();
\f
/*************************************<->*************************************
*
* xrEditor *
* XrPushButton (pushButton, message, data)
*
* xrEditor * pushButton;
* INT32 message;
* INT8 * data;
*
* Description:
* -----------
* This is the main entry point and message handler for the push button
* field editor. It takes all messgae requests, and passes them onto
* the appropriate handler; invalid messages will fail and return an
* error.
*
*
* Inputs:
* ------
* pushButton = For all messages but MSG_NEW and MSG_SIZE, this
* contains the instance pointer.
*
* message = This indicates which action the editor should perform.
*
* data = This is the message specific data. It's usage depends upon
* the 'message' parameter, and may be a scalar or a pointer.
*
* Outputs:
* -------
* Upon successful completion of a command, the instance pointer
* is returned; additional information may be returned by means
* of the 'data' parameter.
*
* Upon failure, NULL is returned, and xrErrno is set.
*
* Procedures Called
* -----------------
* _MsgNew() [MsgCommon.c]
* _MsgFree() [MsgCommon.c]
* _MsgGetState() [MsgCommon.c]
* _MsgSetState() [MsgCommon.c]
* _MsgRedraw() [MsgCommon.c]
* _MsgEdit() [MsgCommon.c]
* _MsgGetItemStates() [MsgItem.c]
* _MsgSetItemStates() [MsgItem.c]
* _MsgGetItemCount() [MsgItem.c]
* _MsgGetItemRects() [MsgItem.c]
* _MsgSize() [MsgItem.c]
* _MsgMove() [MsgItem.c]
* XrCopyRect() [calc.c]
* _XrMakeInvisible() [editorUtil.c]
* XrEditorGroup() [group.c]
* createPButton()
* drawPButton()
* processPButton()
*
*************************************<->***********************************/
xrEditor *
XrPushButton (pushButton, message, data)
register xrEditor * pushButton;
INT32 message;
INT8 * data;
{
/* Determine the action being requested */
switch (message)
{
case MSG_NEW:
{
/*
* Create a new push button editor instance.
* The only parameter of interest is the 'data'
* parameter, which is a pointer to a filled
* instance of the xrPushButtonInfo structure.
*/
return ((xrEditor *) _MsgNew (pushButton, data,
sizeof(xrPushButtonData),
createPButton, drawPButton,
pbFreeMemory, XrPushButton,
XrALLBUTTONS));
}
case MSG_FREE:
{
/*
* Destroy the specified push button instance.
* The 'pushButton' parameter specifies the instance to
* be destroyed; the 'data' parameter is unused.
*/
return ((xrEditor *) _MsgFree (pushButton, pbFreeMemory));
}
case MSG_GETSTATE:
{
/*
* Return the settings of the state flags for the
* specified push button instance. The 'pushButton'
* parameter specifies the instance to be queried, while
* the 'data' parameter must point to an INT8 value, into
* which the state flags will be placed.
*/
return ((xrEditor *) _MsgGetState (pushButton, data));
}
case MSG_SETSTATE:
{
/*
* Change the state flag settings for the specified
* instance. The 'pushButton' parameter specifies the
* instance to be modified, and the 'data' parameter is
* interpreted as an INT8 value, containing the new state
* flag settings.
*/
return ((xrEditor *) _MsgSetState (pushButton, data,
drawPButton, XrALLBUTTONS));
}
case MSG_GETITEMSTATES:
{
/*
* Return the state flags for the individual push buttons.
* The 'pushButton' parameter specifies the instance to be
* queried, while the 'data' parameter must point to an array
* of INT8 values, into which the state flags will be placed.
*/
return ((xrEditor *) _MsgGetItemStates(pushButton, data));
}
case MSG_SETITEMSTATES:
{
/*
* Set the individual button states; redraw only those
* whose state has then changed. The 'pushButton' parameter
* specifies the instance to be modified, while the 'data'
* parameter points to an array of INT8 values, containing
* the new state flags.
*/
return ((xrEditor *)_MsgSetItemStates(pushButton, data, drawPButton));
}
case MSG_GETITEMCOUNT:
{
/*
* Return the number of push buttons in the specified instance.
* The 'pushButton' parameter specifies the instance to be
* queried, while the 'data' parameter must point to an INT32
* value, into which the item count will be placed.
*/
return ((xrEditor *) _MsgGetItemCount (pushButton, data));
}
case MSG_GETITEMRECTS:
{
/*
* Fill the array passed in by the application, with the
* rectangle information describing each push button in
* the specified instance. The 'pushButton' parameter
* indicates the instance to be queried, while the 'data'
* parameter must point to an array of RECTANGLE structures,
* into which the individual button rectangles will be placed.
*/
return ((xrEditor *) _MsgGetItemRects (pushButton, data));
}
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 'data'
* parameter must point to a partially filled out instance
* of the 'xrPushButtonInfo' structure; upon completion,
* the 'editorRect' field of the 'info' structure will be
* filled.
*/
return ((xrEditor *) _MsgSize (data, calcButtonComponents));
}
case MSG_MOVE:
{
/*
* Relocate an instance of push buttons to a new location.
* The 'pushButton' parameter specifies the instance to be
* moved, while the 'data' parameter must point to a POINT
* structure, containing the new editor rectangle origin.
*/
return ((xrEditor *) _MsgMove (pushButton, data, drawPButton));
}
case MSG_RESIZE:
{
/*
* Resize an existing instance of push buttons.
* The 'pushButton' parameter indicates the instance to be
* resized, while the 'data' parameter must point to a
* RECTANGLE structure, containing the new editor rectangle
* definition.
*/
RECTANGLE workRect;
xrPushButtonInfo pbInfo;
register xrPushButtonData * pbDataPtr;
register xrPushButtonInfo * pbInfoPtr;
if (pushButton == NULL)
{
xrErrno = XrINVALIDID;
return ((xrEditor *) NULL);
}
else if (data == NULL)
{
xrErrno = XrINVALIDPTR;
return ((xrEditor *) NULL);
}
/* Create a pseudo Info structure */
pbDataPtr = (xrPushButtonData *) pushButton->editorData;
XrCopyRect (&pushButton->editorRect, &workRect);
pbInfoPtr = &pbInfo;
XrCopyRect ((RECTANGLE *) data, &pbInfoPtr->editorRect);
pbInfoPtr->editorFont = pbDataPtr->pbFont.fontInfo;
pbInfoPtr->numFields = pbDataPtr->pbNumFields;
pbInfoPtr->numCols = pbDataPtr->pbNumCols;
pbInfoPtr->labels = pbDataPtr->pbLabels;
pbInfoPtr->borderWidth = pbDataPtr->pbBorder;
pbInfoPtr->defaultButton = pbDataPtr->pbDefaultButton;
if (createPButton (pbDataPtr, pbInfoPtr, MSG_RESIZE) == FALSE)
return ((xrEditor *) NULL);
XrCopyRect (&pbInfoPtr->editorRect, &pushButton->editorRect);
if (pushButton->editorState & XrVISIBLE)
{
/* Remove the instance from the window */
_XrMakeInvisible (pushButton->editorWindowId, &workRect, TRUE);
/* Redisplay the instance */
drawPButton (pushButton, XrALLBUTTONS);
}
/* Force the editor group rectangle to be recalculated */
XrEditorGroup (NULL, MSG_ADJUSTGROUPRECT, pushButton);
return (pushButton);
}
case MSG_REDRAW:
{
/*
* Redraw a push button instance.
* The 'pushButton' parameter specifies the instance to redraw,
* while the 'data' parameter is interpreted as an INT32 value,
* specifying the type of redraw to perform.
*/
return ((xrEditor *) _MsgRedraw (pushButton, data,
drawPButton, XrALLBUTTONS));
}
case MSG_EDIT:
{
/*
* Process the incoming event, and generate a return
* event, to indicate to the application program
* how the editor instance was modified. The 'data'
* parameter must point to the event to be processed.
*/
return ((xrEditor *) _MsgEdit (pushButton, data,
processPButton, XrPUSHBUTTON));
}
default:
/* All other commands are invalid */
xrErrno = XrINVALIDMSG;
return ((xrEditor *)NULL);
} /* end of switch */
} /* end of XrPushButton() */
\f
/*************************************<->*************************************
*
* INT32
* pbFreeMemory (pbDataPtr)
*
* xrPushButtonData * pbDataPtr;
*
* Description:
* -----------
* This routine is called both when an existing instance is freed,
* and when a MSG_NEW request fails after createPButton() has been
* called. It will free up all resources which createPButton()
* allocated for the instance.
*
*
* Inputs:
* ------
* pbDataPtr = Pointer to the instance's internal 'data' structure.
*
* Outputs:
* -------
*
* Procedures Called
* -----------------
* XFreePixmap() [libX.a]
*
*************************************<->***********************************/
static
INT32
pbFreeMemory (pbDataPtr)
xrPushButtonData * pbDataPtr;
{
if (pbDataPtr->pbTileId != xrDefaultTile)
XFreePixmap (pbDataPtr->pbTileId);
(*xrFree) (pbDataPtr->pbFields);
}
\f
/*************************************<->*************************************
*
* INT32
* calcButtonComponents (pbInfoPtr, fields, cmd)
*
* xrPushButtonInfo * pbInfoPtr;
* xrItemData * fields;
* INT32 cmd;
*
* Description:
* -----------
* If the 'cmd' parameter is set to MSG_SIZE, then this routine will
* calculate the size of the editor rectangle needed to contain the
* instance described by the structure pointed to by 'pbInfoPtr; the
* editor rectangle information is returned in the 'editorRect' field
* within the structure pointed to by the 'pbInfoPtr' parameter.
* If the 'cmd' parameter is set to MSG_NEW, then this routine will
* calculate the location and size of each push button rectangle and
* corresponding button label; this information is then stored in the
* structure pointed to by the 'fields' parameter.
*
*
* Inputs:
* ------
* rbInfoPtr = This points to an instance of the push button 'info'
* structure, which describes the instance being sized
* or created.
*
* fields = This must point to an array of structures, which will be
* used to store temporary information, if 'cmd' is set to
* MSG_SIZE, or will be used to store the component
* information, if 'cmd' is set to MSG_NEW.
*
* cmd = This indicates whether just the size of the editor rectangle
* needs to be calculated (MSG_SIZE), or whether the size and
* location of each component must be calculated (MSG_NEW).
*
* Outputs:
* -------
* Upon successful completion, TRUE is returned, along with some
* additional information in either the 'pbInfoPtr' structure,
* or the 'fields' structure.
*
* Upon failure, FALSE is returned, and xrErrno is set.
*
* Procedures Called
* -----------------
* _XrTextInfo() [textUtil.c]
* XrCopyRect() [calc.c]
* XrStringWidth() [utilities.c]
* XrOffsetRect() [calc.c]
*
*************************************<->***********************************/
static
INT32
calcButtonComponents (pbInfoPtr, fields, cmd)
register xrPushButtonInfo * pbInfoPtr;
register xrItemData * fields;
INT32 cmd;
{
INT16 numFields = pbInfoPtr->numFields;
INT16 numCols = pbInfoPtr->numCols;
INT16 borderWidth = pbInfoPtr->borderWidth;
INT16 numRows;
RECTANGLE * rectPtr = &(pbInfoPtr->editorRect);
register INT8 * end, * start;
FontInfo * fontPtr;
xrTextInfo fontData;
RECTANGLE workRect;
register INT32 i, j;
INT32 lineCount, maxLen;
INT16 border;
INT16 hPadding, vPadding;
INT16 xSize, ySize;
register INT16 maxX, maxY;
INT16 xPos, yPos;
INT16 colWid, rowHt, lineHt;
INT16 stringWidth;
INT16 dftButton;
/* Check for invalid dimensions */
if ((numFields < numCols) || (borderWidth <= 0) ||
(numFields <= 0) || (numCols <= 0))
{
xrErrno = XrINVALIDPARM;
return (FALSE);
}
/* Initialize variables we'll need for our calculations */
numRows = (numFields + numCols - 1) / numCols;
fontPtr = pbInfoPtr->editorFont ? pbInfoPtr->editorFont : xrBaseFontInfo;
_XrTextInfo (fontPtr, &fontData);
lineHt = fontData.ascent + fontData.descent + fontData.leading;
XrCopyRect (&xrZeroRect, &workRect);
rectPtr = &(pbInfoPtr->editorRect);
border = borderWidth << 1;
hPadding = 3 * borderWidth;
vPadding = 3 * borderWidth;
dftButton = pbInfoPtr->defaultButton;
/*
* For each button in this instance, determine the number of lines
* of text in the label, along with the length of the longest line
* in the label. Then, we'll use this information to determine the
* preliminary size of the rectangle needed to contain the button.
*/
for (i = 0; i < numFields; i++)
{
if ((pbInfoPtr->labels) && (pbInfoPtr->labels[i]))
{
/* Determine the number of lines in the label, and the length */
for (lineCount = 0, end = pbInfoPtr->labels[i], maxLen = 0,
start = end;;)
{
/* Check for the end of a line */
if ((*end == '\n') || (*end == NULL))
{
/* End of line encountered */
lineCount++;
/* See if this is the longest line yet in the label */
stringWidth = XrStringWidth (fontPtr, start,
end - start, 0, 0);
if (stringWidth > maxLen)
maxLen = stringWidth;
/* Stop if the end of the string was encountered */
if (*end == NULL)
break;
/* Skip over the Newline, and continue */
start = ++end;
continue;
}
/* Advance to next character */
end++;
}
}
else
{
/* This button has no label */
lineCount = 0;
maxLen = 0;
}
/* We can now determine the preliminary size of the button */
ySize = (i == dftButton ? border << 1 : border) +
(lineHt * lineCount) + vPadding;
xSize = (i == dftButton ? border << 1 : border) +
maxLen + ySize + hPadding;
workRect.width = xSize;
workRect.height = ySize;
XrCopyRect (&workRect, &((fields + i)->rectangle));
}
/*
* At this point, we will adjust each button within a row, so that
* they all have the same height.
*/
for (i = 0; i < numFields; i += numCols)
{
/* Find the button with the highest height in each row */
maxY = 0;
for (j = i; j < i + numCols && j < numFields; j++)
{
if (maxY < (fields + j)->rectangle.height)
maxY = (fields + j)->rectangle.height;
}
/* Set the height of all buttons in the row to this max value */
for (j = i; j < i + numCols && j < numFields; j++)
(fields + j)->rectangle.height = maxY;
}
/*
* Now, we need to adjust each button in a column, so that they
* all have the same width.
*/
for (i = 0; i < numCols; i++)
{
/* Find the button with the largest width in each column */
maxX = maxY = 0;
for (j = i; j < numFields; j += numCols)
{
if (maxX < (fields + j)->rectangle.width)
maxX = (fields + j)->rectangle.width;
if (maxY < (fields + j)->rectangle.height)
maxY = (fields + j)->rectangle.height;
}
/* Make sure the buttons end up proportionally sized */
if (maxX < (maxY << 1))
maxX = maxY << 1;
/* Adjust the width of all buttons in this column */
for (j = i; j < numFields; j+= numCols)
(fields + j)->rectangle.width = maxX;
}
/*
* Determine the total height and width of the instance, by
* adding up the width of one row, and the height of one column.
*/
for (i = maxX = 0; i < numCols; i++)
maxX += (fields + i)->rectangle.width;
for (i = maxY = 0; i < numFields; i += numCols)
maxY += (fields + i)->rectangle.height;
/*
* If this is only a size request, then use some default padding
* values to space out the buttons, and then return the size
* of the rectangle which would enclose the whole instance, int
* the editorRect portion of the Init structure.
*/
if (cmd == MSG_SIZE)
{
/* Calculate the default padding values */
hPadding = (fontData.maxWidth << 1) * (numCols - 1);
vPadding = lineHt * (numRows - 1);
/* Set the rectangle values */
XrCopyRect (&xrZeroRect, rectPtr);
rectPtr->width = hPadding + maxX;
rectPtr->height = vPadding + maxY;
return (TRUE);
}
/*
* Otherwise, this is a create request, so determine how much extra
* space is available in the specified editorRect, and use it as
* padding between each of the buttons.
*/
hPadding = (rectPtr->width - maxX) / ((numCols == 1) ? 1 : numCols - 1);
vPadding = (rectPtr->height - maxY) / ((numRows == 1) ? 1 : numRows - 1);
/* Position each button within a row, starting at top left corner */
xPos = rectPtr->x;
yPos = rectPtr->y;
for (i = 0; i < numFields; i+= numCols)
{
rowHt = (fields + i)->rectangle.height;
colWid = 0;
for (j = i; j < i + numCols && j < numFields; j++)
{
XrOffsetRect (&((fields + j)->rectangle), colWid + xPos, yPos);
colWid += hPadding + ((fields + j)->rectangle.width);
}
/* Repeat for the next row */
yPos += vPadding + rowHt;
}
return (TRUE);
}
\f
/*************************************<->*************************************
*
* INT32
* createPButton (pbDataPtr, pbInfoPtr, message)
*
* xrPushButtonData * pbDataPtr;
* xrPushButtonInfo * pbInfoPtr;
* INT32 message;
*
* Description:
* -----------
* if (message == MSG_NEW)
* This routine is responsible for creating a new push button instance.
* The description of the new instance is contained within the structure
* pointed to by the 'pbInfoPtr' parameter. Besides allocating the
* resources needed for the new instance, this procedure will also fill
* in the structure pointed to by the 'pbDataPtr' parameter with the
* state information for the new instance.
*
* if (message == MSG_RESIZE)
* This routine will take the information contained within the
* 'pbInfoPtr' structure, and will recalculate the location of each
* component within an existing instance of push buttons, to match
* the new data. This will do no resource allocation.
*
*
* Inputs:
* ------
* pbDataPtr = Points to the 'data' structure for the instance being
* created or resized.
*
* pbInfoPtr = Points to the 'info' structure, which describes how the
* instance is to be laid out.
*
* message = This can be set to MSG_NEW or MSG_RESIZE.
*
* Outputs:
* -------
* Upon successful completion, TRUE is returned, and the 'pbDataPtr'
* structure is filled out.
*
* Upon failure, FALSE is returned, and xrErrno is set.
*
* Procedures Called
* -----------------
* XrResource() [resource.c]
* XMakePixmap() [libX.a]
* XFreePixmap() [libX.a]
* XrCopyRect() [calc.c]
* XrSetPt() [calc.c]
* _XrTextInfo() [textUtil.c]
* calcButtonComponents()
*
*************************************<->***********************************/
static
INT32
createPButton (pbDataPtr, pbInfoPtr, message)
register xrPushButtonData * pbDataPtr;
register xrPushButtonInfo * pbInfoPtr;
int message;
{
FontInfo * fontPtr;
register xrItemData * aButton;
register INT16 i;
xrResourceInfo bitmapInfo;
RECTANGLE editorRect;
RECTANGLE minRect;
xrItemData * tempItems;
/*
* Allocate some space to hold the calculations performed
* when we check the rectangle size.
*/
if ((tempItems = (xrItemData *) (*xrMalloc)
(sizeof (xrItemData) * pbInfoPtr->numFields)) == NULL)
{
/* Unable to allocate the memory we need */
xrErrno = XrOUTOFMEM;
return (FALSE);
}
if (message == MSG_NEW)
{
/* Allocate space to hold the individual button information */
if ((pbDataPtr->pbFields = (xrItemData *) (*xrMalloc)
(sizeof (xrItemData) * pbInfoPtr->numFields)) == NULL)
{
/* Unable to allocate the memory we need */
(*xrFree)(tempItems);
xrErrno = XrOUTOFMEM;
return (FALSE);
}
pbDataPtr->pbFGColor = (pbInfoPtr->editorFGColor == -1) ?
xrForegroundColor : pbInfoPtr->editorFGColor;
pbDataPtr->pbBGColor = (pbInfoPtr->editorBGColor == -1) ?
xrBackgroundColor : pbInfoPtr->editorBGColor;
/* Create the 50% tile we will need when drawing insensitive buttons */
if ((pbInfoPtr->editorFGColor == -1) &&
(pbInfoPtr->editorBGColor == -1))
{
/* Use the default 50% tile */
pbDataPtr->pbTileId = xrDefaultTile;
}
else
{
bitmapInfo.resourceType = XrTYPE_BITMAPID;
bitmapInfo.resourceId = XrPERCENT50;
if ((XrResource (MSG_FIND, &bitmapInfo) == FALSE) ||
((pbDataPtr->pbTileId =
XMakePixmap (((xrBitmapId *) bitmapInfo.resourceObject)->bitmapId,
pbDataPtr->pbFGColor, pbDataPtr->pbBGColor)) == 0))
{
/* Unable to create the tile */
(*xrFree)(tempItems);
(*xrFree) (pbDataPtr->pbFields);
xrErrno = XrXCALLFAILED;
return (FALSE);
}
}
}
/* Check the rectangle size */
XrCopyRect (&pbInfoPtr->editorRect, &editorRect);
if (calcButtonComponents (pbInfoPtr, tempItems, MSG_SIZE) == FALSE)
{
/* The application must have supplied invalid information */
/* xrErrno is set by calcButtonComponents */
XrCopyRect (&editorRect, &pbInfoPtr->editorRect);
(*xrFree)(tempItems);
if (message == MSG_NEW)
{
if (pbDataPtr->pbTileId != xrDefaultTile)
XFreePixmap (pbDataPtr->pbTileId);
(*xrFree) (pbDataPtr->pbFields);
}
return (FALSE);
}
(*xrFree)(tempItems);
XrCopyRect (&pbInfoPtr->editorRect, &minRect);
XrCopyRect (&editorRect, &pbInfoPtr->editorRect);
if ((editorRect.height < minRect.height) ||
(editorRect.width < minRect.width))
{
/* The application supplied an invalid rectangle */
xrErrno = XrINVALIDRECT;
if (message == MSG_NEW)
{
if (pbDataPtr->pbTileId != xrDefaultTile)
XFreePixmap (pbDataPtr->pbTileId);
(*xrFree) (pbDataPtr->pbFields);
}
return (FALSE);
}
/* Generate the location and size information associated with each button */
calcButtonComponents (pbInfoPtr, pbDataPtr->pbFields, MSG_NEW);
if (message == MSG_NEW)
{
/* Fill in the rest of the fields in the button structures */
pbDataPtr->pbNumFields = pbInfoPtr->numFields;
pbDataPtr->pbNumCols = pbInfoPtr->numCols;
fontPtr = pbInfoPtr->editorFont ? pbInfoPtr->editorFont : xrBaseFontInfo;
_XrTextInfo (fontPtr, &pbDataPtr->pbFont);
pbDataPtr->pbBorder = pbInfoPtr->borderWidth;
pbDataPtr->pbLabels = pbInfoPtr->labels;
pbDataPtr->pbActiveButton = -1;
pbDataPtr->pbStates = pbInfoPtr->stateFlags;
pbDataPtr->pbDefaultButton = pbInfoPtr->defaultButton;
aButton = pbDataPtr->pbFields;
for (i = 0; i < pbDataPtr->pbNumFields; i++, aButton++)
{
/* Copy over each button label */
if (pbInfoPtr->labels)
aButton->label = pbInfoPtr->labels[i];
else
aButton->label = NULL;
/* Copy the initial state flags */
if (pbInfoPtr->stateFlags)
aButton->state = pbInfoPtr->stateFlags[i];
else
aButton->state = (XrVISIBLE | XrSENSITIVE);
/* Set unused fields to zeros */
XrCopyRect (&xrZeroRect, &(aButton->subRectangle));
XrSetPt (&(aButton->labelPt), 0, 0);
}
}
return (TRUE);
}
\f
/*************************************<->*************************************
*
* INT32
* drawPButton (pushButton, buttonNum)
*
* xrEditor * pushButton;
* INT32 buttonNum;
*
* Description:
* -----------
* This routine will display either a single push button, or all
* of the push buttons, depending upon the value specified in the
* 'buttonNum' parameter.
*
*
* Inputs:
* ------
* pushButton = Points to the editor instance structure.
*
* buttonNum = This can be set to the index of the button to be drawn,
* or to the define XrALLBUTTONS, if all the buttons should
* be redrawn.
*
* Outputs:
* -------
*
* Procedures Called
* -----------------
* _XrMakeInvisible() [editorUtil.c]
* XrCopyRect() [rectUtil.c]
* _XrFillOval() [ovalUtil.c]
* _XrOval() [ovalUtil.c]
* displayButtonLabel()
* pbSetUpGCs()
*
*************************************<->***********************************/
static
INT32
drawPButton (pushButton, buttonNum)
xrEditor * pushButton;
INT32 buttonNum;
{
register xrPushButtonData * pbDataPtr;
Window windowId;
INT32 sensitive;
register INT16 firstButton, lastButton;
register xrItemData * aButton;
RECTANGLE workRect;
register RECTANGLE * workRectPtr;
register INT16 buttonBorder;
INT8 makeGCFlag;
INT16 dftButton;
INT32 borderGC;
INT8 drawLabelSensitive;
INT8 activeFlag;
/* Initialize variables */
pbDataPtr = (xrPushButtonData *) pushButton->editorData;
windowId = pushButton->editorWindowId;
workRectPtr = &workRect;
makeGCFlag = TRUE;
dftButton = pbDataPtr->pbDefaultButton;
/*
* If the instance is not visible, then fill its area with the
* background tile for the port, thus making the instance invisible.
*/
if (!(pushButton->editorState & XrVISIBLE))
{
_XrMakeInvisible (windowId, &pushButton->editorRect, TRUE);
return;
}
/* Set up the graphic contexts needed for drawing */
pbSetUpGCs (pbDataPtr);
sensitive = (pushButton->editorState & XrSENSITIVE) ? TRUE : FALSE;
/* Determine the range of buttons to be drawn */
if (buttonNum == XrALLBUTTONS)
{
firstButton = 0;
lastButton = pbDataPtr->pbNumFields - 1;
}
else
firstButton = lastButton = buttonNum;
while (firstButton <= lastButton)
{
activeFlag = (firstButton == pbDataPtr->pbActiveButton) ? TRUE:FALSE;
aButton = (pbDataPtr->pbFields) + firstButton;
XrCopyRect (&(aButton->rectangle), workRectPtr);
/* Determine how to draw the button, depending upon it's state */
if (aButton->state & XrVISIBLE)
{
/* Select which graphics context to use for the border */
if (dftButton == firstButton)
{
/* Dft button has double high border */
buttonBorder = pbDataPtr->pbBorder << 1;
borderGC = xrEditorGC4;
}
else
{
/* Regular buttons have single high border */
buttonBorder = pbDataPtr->pbBorder;
borderGC = xrEditorGC3;
}
/*
* Modify the oval definition, so that the borders
* will be properly drawn.
*/
workRectPtr->height -= buttonBorder;
workRectPtr->width -= buttonBorder;
if (sensitive && (aButton->state & XrSENSITIVE))
{
/* Determine if the button is active or inactive */
if (activeFlag)
{
/*
* The state of the button is 'ACTIVE', so draw
* it as a filled oval, using the foreground color.
*/
draw1Button (windowId, xrEditorGC1, borderGC, workRectPtr);
}
else
{
/*
* The state of the button is 'INACTIVE', so draw
* draw the oval with the border in the foreground
* color, and the interior in the background color.
*/
draw1Button (windowId, xrEditorGC2, borderGC, workRectPtr);
}
/* Flag that this label should be drawn as sensitive */
drawLabelSensitive = TRUE;
}
else
{
/*
* The button is insensitive, so we will draw it as a
* filled oval, using the 50% tile.
*/
draw1Button (windowId, xrEditorGC3, borderGC, workRectPtr);
/* Flag that the label should not be drawn as sensitive */
drawLabelSensitive = FALSE;
}
/*
* If the button has a label, then we will draw that
* now. The pens to be used for drawing the label
* have already been set up above, when the oval
* was drawn.
*/
if ((aButton->label) && (strlen(aButton->label) > 0))
displayButtonLabel (windowId, pbDataPtr, aButton,
drawLabelSensitive, activeFlag);
}
else
{
/*
* The button is not visible, so fill the area it would occupy
* with the window's background color.
*/
_XrMakeInvisible (windowId, workRectPtr, makeGCFlag);
makeGCFlag = FALSE;
}
/* Go on and process the next button */
firstButton++;
}
}
\f
/*************************************<->*************************************
*
* INT32
* displayButtonLabel (windowId, pbDataPtr, aButton, drawSensitive,
* activeFlag)
*
* Description:
* -----------
* This routine displays the label within a particular push button.
* The 'aButton' parameter points to a structure containing the label
* and the button location information. If the button is not sensitive
* then the label is drawn as hatched. This routine assumes that all
* of the necessary graphic contexts have already been initialized.
*
*
* Inputs:
* ------
* windowId = Id of window to which the instance is attached.
*
* pbDataPtr = Points to the instance's internal 'data' structure.
* This is used to access the font information.
*
* aButton = Points to the 'item' structure associated with the
* push button whose label is being displayed.
*
* drawSensitive = TRUE if the button is sensitive; FALSE otherwise.
*
* activeFlag = TRUE if the push button is currently active; FALSE
* otherwise.
*
* Outputs:
* -------
*
* Procedures Called
* -----------------
* XrStringWidth() [utilities.c]
* _XrImageText8() [textUtil.c]
*
*************************************<->***********************************/
static
INT32
displayButtonLabel (windowId, pbDataPtr, aButton, drawSensitive, activeFlag)
Window windowId;
xrPushButtonData * pbDataPtr;
register xrItemData * aButton;
INT8 drawSensitive;
INT8 activeFlag;
{
register INT8 * start;
register INT8 * end;
xrTextInfo * fontPtr = &(pbDataPtr->pbFont);
INT16 lineHt;
INT16 xCenter, yCenter;
register INT16 penX, penY;
INT32 lineCount;
INT32 gc;
/* Find the center of the button */
lineHt = fontPtr->ascent + fontPtr->descent + fontPtr->leading;
xCenter = (aButton->rectangle.width >> 1) + aButton->rectangle.x;
yCenter = (aButton->rectangle.height >> 1) + aButton->rectangle.y;
/* Determine the number of lines in the label */
lineCount = 1;
start = aButton->label;
while (*start != NULL)
{
if (*start == '\n')
lineCount ++;
start++;
}
/* Set the pen position for the start of the label */
yCenter -= (lineHt * lineCount) >> 1;
penX = xCenter;
penY = yCenter;
/* Display the label */
for (start = end = aButton->label;;)
{
if ((*end == '\n') || (*end == NULL))
{
penX -= (XrStringWidth (fontPtr->fontInfo, start, end-start,0,0)) >> 1;
/*
* Draw the button label. The technique used to do this
* will depend upon whether the label is drawn in a sensitive
* or an insensitive push button. If the button is sensitive,
* then the label is simple drawn using the foreground and
* background colors. If the button is not sensitive, then
* the label is drawn several times, so that it is patterned
* on top of the 50% background pattern.
*/
if (drawSensitive)
{
/* Draw the label as sensitive */
if (activeFlag)
gc = xrEditorGC2;
else
gc = xrEditorGC1;
_XrImageText8 (windowId, gc, end-start, penX, penY, start);
}
else
{
/* Draw the label as insensitive */
_XrImageText8 (windowId, xrEditorGC5, end-start,
penX, penY, start);
_XrImageText8 (windowId, xrEditorGC6, end-start,
penX, penY, start);
}
if (*end == NULL)
break;
start = ++end;
penY += lineHt;
penX = xCenter;
continue;
}
end++;
}
}
\f
/*************************************<->*************************************
*
* INT32
* processPButton (pushButton, input, returnEvent)
*
* xrEditor * pushButton;
* XButtonEvent * input;
* xrEvent * returnEvent;
*
* Description:
* -----------
* This is the event processing routine for the push button editor.
* It takes an event, and determines which, if any, of the push
* buttons was selected. If a push button was selected, then it
* will be draw as 'active', and we will then wait for the user to
* release the select button; at that time, the button will be redrawn
* as 'inactive'.
*
*
* Inputs:
* ------
* pushButton = This is the instance pointer for the instance in
* which the event occurred.
*
* input = This points to the event to be processed.
*
* returnEvent = This points to a partially filled out X-ray event
* structure. It can be used by this routine when it
* needs to generate a return event for the application.
* Every field is already filled out, except for the
* 'value' fields. When this routine returns to _MsgEdit()
* this event is pushed onto the front of the input queue.
*
* Outputs:
* -------
* Although a value is not directly returned, an input event will be
* generated, which tells the applicating which push button was
* selected. This event is then pushed onto the input queue by
* _MsgEdit().
*
* Procedures Called
* -----------------
* XrSetPt() [calc.c]
* XrInput() [input.c]
* drawPButton()
*
*************************************<->***********************************/
static
INT32
processPButton (pushButton, input, returnEvent)
xrEditor * pushButton;
XButtonEvent * input;
xrEvent * returnEvent;
{
register xrPushButtonData * pbDataPtr;
POINT spritePt;
register INT16 i;
register xrItemData * aButton;
XEvent exitEvent;
pbDataPtr = (xrPushButtonData *) pushButton->editorData;
XrSetPt (&spritePt, input->x, input->y);
returnEvent->value1 = NULL;
/* Check each button to see if one was selected */
for (i = 0; i < pbDataPtr->pbNumFields; i++)
{
aButton = (pbDataPtr->pbFields) + i;
if (XrPtInRect (&spritePt, &(aButton->rectangle)) &&
((aButton->state & (XrVISIBLE | XrSENSITIVE)) ==
(XrVISIBLE | XrSENSITIVE)))
{
/* A button was selected; modify its value and redraw it */
pbDataPtr->pbActiveButton = i;
drawPButton (pushButton, i);
/* Wait for the select up event */
while (XrInput (NULL, MSG_BLKREAD, &exitEvent) == FALSE);
XrInput (NULL, MSG_PUSHEVENT, &exitEvent);
pbDataPtr->pbActiveButton = -1;
drawPButton (pushButton, i);
/* Save the index of the button which changed, and return */
returnEvent->value2 = i;
returnEvent->value1 = XrSELECT;
}
}
}
\f
/*************************************<->*************************************
*
* INT32
* pbSetUpGCs (pbDataPtr)
*
* xrPushButtonData * pbDataPtr;
*
* Description:
* -----------
* This routine sets up the 6 graphic contexts which may be needed
* whenever a push button instance is drawn.
*
*
* Inputs:
* ------
* pbDataPtr = Points to the instance's 'data' structure; this
* contains the color and font information.
*
* Outputs:
* -------
*
* Procedures Called
* -----------------
* _XrInitEditorGCs() [gcUtil.c]
* _XrCopyGC() [gcUtil.c]
* _XrChangeGC() [gcUtil.c]
*
*************************************<->***********************************/
static
INT32
pbSetUpGCs (pbDataPtr)
register xrPushButtonData * pbDataPtr;
{
INT32 changeList[21];
INT32 changeMask;
/* Initialize the standard graphic contexts (1 & 2) we will be using */
_XrInitEditorGCs (pbDataPtr->pbFGColor, pbDataPtr->pbBGColor,
pbDataPtr->pbFont.fontInfo->id);
/* Set the values we need for the border graphics context */
_XrCopyGC (xrDefaultGC, xrEditorGC3);
changeList[XrFOREGROUNDVAL] = pbDataPtr->pbFGColor;
changeList[XrBACKGROUNDVAL] = pbDataPtr->pbBGColor;
changeList[XrFONTVAL] = pbDataPtr->pbFont.fontInfo->id;
changeList[XrLINEWIDTHVAL] = pbDataPtr->pbBorder;
changeList[XrTILEVAL] = pbDataPtr->pbTileId;
changeList[XrFILLSTYLEVAL] = Tiled;
changeMask = (XrFOREGROUND | XrBACKGROUND | XrFONT | XrLINEWIDTH |
XrTILE | XrFILLSTYLE);
_XrChangeGC (xrEditorGC3, changeMask, changeList);
/*
* If a default button is specified, then we will need an
* additional graphics context, to handle drawing the double
* wide button border.
*/
_XrCopyGC (xrEditorGC3, xrEditorGC4);
changeList[XrLINEWIDTHVAL] = pbDataPtr->pbBorder << 1;
_XrChangeGC (xrEditorGC4, XrLINEWIDTH, changeList);
/*
* We will need 2 additional graphic contexts, which will be
* used to draw the label for an insensitive push button.
*/
_XrCopyGC (xrDefaultGC, xrEditorGC5);
changeList[XrFOREGROUNDVAL] = 0;
changeList[XrBACKGROUNDVAL] = AllPlanes;
changeList[XrFONTVAL] = pbDataPtr->pbFont.fontInfo->id;
changeList[XrALUVAL] = GXand;
changeMask = (XrFOREGROUND | XrBACKGROUND | XrFONT | XrALU);
_XrChangeGC (xrEditorGC5, changeMask, changeList);
_XrCopyGC (xrDefaultGC, xrEditorGC6);
changeList[XrFOREGROUNDVAL] = pbDataPtr->pbFGColor;
changeList[XrBACKGROUNDVAL] = 0;
changeList[XrFONTVAL] = pbDataPtr->pbFont.fontInfo->id;
changeList[XrALUVAL] = GXor;
changeMask = (XrFOREGROUND | XrBACKGROUND | XrFONT | XrALU);
_XrChangeGC (xrEditorGC6, changeMask, changeList);
}
\f
/*************************************<->*************************************
*
* draw1Button (windowId, fillGC, borderGC, rectPtr)
*
* Window windowId;
* INT32 fillGC;
* INT32 borderGC;
* RECTANGLE * rectPtr;
*
* Description:
* -----------
* This routines draws and fills a single push button. The button
* is drawn as a 12 sided polygon.
*
*
* Inputs:
* ------
* windowId = Id of window in which button is to be drawn.
*
* fillGC = Graphic context to use to fill the interior of the button.
*
* borderGC = Graphic context to use to draw the button border.
*
* rectPtr = Describes the rectangle in which the button will be drawn.
*
* Outputs:
* -------
*
* Procedures Called
* -----------------
* _XrPoly() [polyUtil.c]
* _XrFillPoly() [polyUtil.c]
*
*************************************<->***********************************/
static
INT32
draw1Button (windowId, fillGC, borderGC, rectPtr)
Window windowId;
INT32 fillGC;
INT32 borderGC;
register RECTANGLE * rectPtr;
{
INT16 rightEdge, bottom;
INT16 oneEighthH, threeEighthsH;
INT16 halfHeight, halfWidth;
INT32 i;
/* Calculate our working values */
rightEdge = rectPtr->x + rectPtr->width - 1;
bottom = rectPtr->y + rectPtr->height - 1;
oneEighthH = rectPtr->height >> 3;
threeEighthsH = (rectPtr->height * 3) >> 3;
halfHeight = rectPtr->y + (rectPtr->height >> 1);
halfWidth = (rectPtr->height >> 1);
/* Fill in the 'flags' field of the polygon structure */
for (i = 0; i < 13; i++)
xr_PolyList[i].flags = 0;
/* Calculate the polygon endpoints */
xr_PolyList[0].x = rectPtr->x + halfWidth - oneEighthH;
xr_PolyList[0].y = rectPtr->y;
xr_PolyList[1].x = rightEdge - halfWidth + oneEighthH;
xr_PolyList[1].y = rectPtr->y;
xr_PolyList[2].x = rightEdge - oneEighthH;
xr_PolyList[2].y = halfHeight - threeEighthsH;
xr_PolyList[3].x = rightEdge;
xr_PolyList[3].y = halfHeight - oneEighthH;
xr_PolyList[4].x = rightEdge;
xr_PolyList[4].y = halfHeight + oneEighthH;
xr_PolyList[5].x = rightEdge - oneEighthH;
xr_PolyList[5].y = halfHeight + threeEighthsH;
xr_PolyList[6].x = rightEdge - halfWidth + oneEighthH;
xr_PolyList[6].y = bottom;
xr_PolyList[7].x = rectPtr->x + halfWidth - oneEighthH;
xr_PolyList[7].y = bottom;
xr_PolyList[8].x = rectPtr->x + oneEighthH;
xr_PolyList[8].y = halfHeight + threeEighthsH;
xr_PolyList[9].x = rectPtr->x;
xr_PolyList[9].y = halfHeight + oneEighthH;
xr_PolyList[10].x = rectPtr->x;
xr_PolyList[10].y = halfHeight - oneEighthH;
xr_PolyList[11].x = rectPtr->x + oneEighthH;
xr_PolyList[11].y = halfHeight - threeEighthsH;
xr_PolyList[12].x = rectPtr->x + halfWidth - oneEighthH;
xr_PolyList[12].y = rectPtr->y;
/* Draw the button */
_XrFillPoly (windowId, fillGC, 13, xr_PolyList);
_XrPoly (windowId, borderGC, 13, xr_PolyList);
}