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