/* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * HISTORY */ #ifdef REV_INFO #ifndef lint static char rcsid[] = "$XConsortium: GeoUtils.c /main/13 1996/08/15 17:11:25 pascale $" #endif #endif /* (c) Copyright 1989, DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. */ /* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */ #ifndef X_NOT_STDC_ENV #include #endif #include "XmI.h" #include "GeoUtilsI.h" #include "GMUtilsI.h" /******** Static Function Declarations ********/ static XtGeometryResult QueryAnyPolicy( XmGeoMatrix geoSpec, XtWidgetGeometry *parentRequestRtn) ; static XtGeometryResult QueryGrowPolicy( XmGeoMatrix geoSpec, XtWidgetGeometry *parentRequestRtn) ; static XtGeometryResult QueryNonePolicy( XmGeoMatrix geoSpec, XtWidgetGeometry *parentRequestRtn) ; static Dimension _XmGeoStretchVertical( XmGeoMatrix geoSpec, #if NeedWidePrototypes int actualH, int desiredH) ; #else Dimension actualH, Dimension desiredH) ; #endif /* NeedWidePrototypes */ static Dimension _XmGeoFillVertical( XmGeoMatrix geoSpec, #if NeedWidePrototypes int actualH, int desiredH) ; #else Dimension actualH, Dimension desiredH) ; #endif /* NeedWidePrototypes */ static void _XmGeoCalcFill( #if NeedWidePrototypes int fillSpace, int margin, #else Dimension fillSpace, Dimension margin, #endif /* NeedWidePrototypes */ unsigned int numBoxes, #if NeedWidePrototypes int endSpec, int betweenSpec, #else Dimension endSpec, Dimension betweenSpec, #endif /* NeedWidePrototypes */ Dimension *pEndSpace, Dimension *pBetweenSpace) ; static int boxWidthCompare( XmConst void *boxPtr1, XmConst void *boxPtr2) ; static void FitBoxesAveraging( XmKidGeometry rowPtr, unsigned int numBoxes, #if NeedWidePrototypes int boxWidth, #else Dimension boxWidth, #endif /* NeedWidePrototypes */ int amtOffset) ; static void FitBoxesProportional( XmKidGeometry rowPtr, unsigned int numBoxes, #if NeedWidePrototypes int boxWidth, #else Dimension boxWidth, #endif /* NeedWidePrototypes */ int amtOffset) ; static void SegmentFill( XmKidGeometry rowBoxes, unsigned int numBoxes, XmGeoRowLayout layoutPtr, #if NeedWidePrototypes int x, int width, int marginW, int endX, int maxX, int endSpace, int betweenSpace) ; #else Position x, Dimension width, Dimension marginW, Position endX, Position maxX, Dimension endSpace, Dimension betweenSpace) ; #endif /* NeedWidePrototypes */ static Position _XmGeoLayoutWrap( XmKidGeometry rowPtr, XmGeoRowLayout layoutPtr, #if NeedWidePrototypes int x, int y, int endSpace, int betweenSpace, int maxX, int width, int marginW) ; #else Position x, Position y, Dimension endSpace, Dimension betweenSpace, Position maxX, Dimension width, Dimension marginW) ; #endif /* NeedWidePrototypes */ static Position _XmGeoLayoutSimple( XmKidGeometry rowPtr, XmGeoRowLayout layoutPtr, #if NeedWidePrototypes int x, int y, int maxX, int endSpace, int betweenSpace) ; #else Position x, Position y, Position maxX, Dimension endSpace, Dimension betweenSpace) ; #endif /* NeedWidePrototypes */ static Position _XmGeoArrangeList( XmKidGeometry rowBoxes, XmGeoRowLayout layoutPtr, #if NeedWidePrototypes int x, int y, int width, int marginW, int marginH) ; #else Position x, Position y, Dimension width, Dimension marginW, Dimension marginH) ; #endif /* NeedWidePrototypes */ /******** End Static Function Declarations ********/ /****************************************************************/ #ifdef DEBUG_GEOUTILS void PrintBox( char * hdr, XmKidGeometry box) ; void PrintList( char * hdr, XmKidGeometry listPtr) ; void PrintMatrix( char * hdr, XmGeoMatrix spec) ; #endif /* DEBUG_GEOUTILS */ /****************************************************************/ XtGeometryResult _XmHandleQueryGeometry( Widget widget, XtWidgetGeometry *intended, XtWidgetGeometry *desired, #if NeedWidePrototypes unsigned int resize_policy, #else unsigned char resize_policy, #endif /* NeedWidePrototypes */ XmGeoCreateProc createMatrix) { Dimension width = 0 ; Dimension height = 0 ; XmGeoMatrix geoSpec ; /* first determine what is the desired size, using the resize_policy. */ if (resize_policy == XmRESIZE_NONE) { desired->width = XtWidth(widget) ; desired->height = XtHeight(widget) ; } else { if (GMode( intended) & CWWidth) width = intended->width; if (GMode( intended) & CWHeight) height = intended->height; geoSpec = (*createMatrix)( widget, NULL, NULL) ; _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &width, &height) ; _XmGeoMatrixFree( geoSpec) ; if ((resize_policy == XmRESIZE_GROW) && ((width < XtWidth(widget)) || (height < XtHeight(widget)))) { desired->width = XtWidth(widget) ; desired->height = XtHeight(widget) ; } else { desired->width = width ; desired->height = height ; } } /* deal with user initial size setting */ if (!XtIsRealized(widget)) { if (XtWidth(widget) != 0) desired->width = XtWidth(widget) ; if (XtHeight(widget) != 0) desired->height = XtHeight(widget) ; } return XmeReplyToQueryGeometry(widget, intended, desired) ; } /****************************************************************/ XtGeometryResult _XmHandleGeometryManager( Widget wid, Widget instigator, XtWidgetGeometry *desired, XtWidgetGeometry *allowed, #if NeedWidePrototypes unsigned int policy, #else unsigned char policy, #endif /* NeedWidePrototypes */ XmGeoMatrix *cachePtr, XmGeoCreateProc createMatrix) { XmGeoMatrix geoSpec ; XtWidgetGeometry parentRequest ; XtGeometryResult queryResult ; XtGeometryResult result ; /****************/ if( !cachePtr ) { /* Almost replies are not entertained unless caching is supported. */ allowed = NULL ; } else { geoSpec = *cachePtr ; if( geoSpec ) { if( (geoSpec->composite == wid) && (geoSpec->instigator == instigator) && _XmGeometryEqual( instigator, geoSpec->in_layout, desired) ) { /* This is a successive geometry request which matches the * cached geometry record. */ if( GMode( desired) & XtCWQueryOnly ) { return( XtGeometryYes) ; } else { /* If we get here, we should have already verified that * the current layout is acceptable to the parent, so * we will ignore the result of the request. */ if( geoSpec->parent_request.request_mode ) { geoSpec->parent_request.request_mode &= ~XtCWQueryOnly ; XtMakeGeometryRequest( wid, &geoSpec->parent_request, NULL) ; } _XmGeoMatrixSet( geoSpec) ; _XmGeoMatrixFree( geoSpec) ; *cachePtr = NULL ; return( XtGeometryYes) ; } } else { /* Cached geometry is different than current request, so clear * existing cache record and allow request to be processed. */ _XmGeoMatrixFree( geoSpec) ; *cachePtr = NULL ; } } } /* Get box list and arrange boxes according to policy. */ geoSpec = (*createMatrix)( wid, instigator, desired) ; if( geoSpec->no_geo_request && (*geoSpec->no_geo_request)( geoSpec) ) { _XmGeoMatrixFree( geoSpec) ; return( XtGeometryNo) ; } /* The following Query routines only respond with XtGeometryYes or * XtGeometryNo. All requests made to the parent are strictly * queries. * A return value (from these routines!) of XtGeometryNo means that * the composite widget would need to change size in order to * entertain the child's request, and that the parent said "no" * to the request. A XtGeometryNo leaves no alternatives to the * child's geometry request. * A return value of XtGeometryYes means that either the composite * widget does not need to change size to entertain the child's * request, or that negotiation with the parent yielded a viable * geometry layout. If the composite widget does not need to * change size, then request_mode field of the returned geometry * structure will contain zero. Otherwise, the returned geometry * structure will contain a request which is guaranteed to be * accepted by a subsequent request to the parent. * A return value of XtGeometryYes always loads the return geometry * structure with valid data. */ switch( policy ) { case XmRESIZE_GROW: { queryResult = QueryGrowPolicy( geoSpec, &parentRequest) ; break; } case XmRESIZE_NONE: { queryResult = QueryNonePolicy( geoSpec, &parentRequest) ; break ; } case XmRESIZE_ANY: default: { queryResult = QueryAnyPolicy( geoSpec, &parentRequest) ; break ; } } result = XtGeometryNo ; /* Setup default response. */ /* If parent replies XtGeometryYes, then build appropriate reply for * instigator. Otherwise, it is not reasonable to try to find a child * size which would result in an acceptable overall size, so just say no. */ if( queryResult == XtGeometryYes ) { if( _XmGeoReplyYes( instigator, desired, geoSpec->in_layout) ) { /* Reply Yes since desired geometry is same as the * instigator geometry in this layout. */ if( GMode( desired) & XtCWQueryOnly ) { geoSpec->parent_request = parentRequest ; result = XtGeometryYes ; } else { /* Don't need almost reply and this is not a query, so do it! */ if( parentRequest.request_mode ) { /* The geometry request in parentRequest has already * been tested by a query to the parent, so should * always be honored. */ parentRequest.request_mode &= ~XtCWQueryOnly ; XtMakeGeometryRequest( wid, &parentRequest, NULL) ; } _XmGeoMatrixSet( geoSpec) ; result = XtGeometryYes ; } } else { /* If allowed and not an exception then reply Almost, since * desired geometry is different than geometry in this layout. */ if( allowed && ( !geoSpec->almost_except || !(*(geoSpec->almost_except))(geoSpec)) ) { geoSpec->parent_request = parentRequest ; result = XtGeometryAlmost ; } } } switch( result ) { case XtGeometryAlmost: { /* Cache "almost" replies. Variables cachePtr and allowed are * guaranteed to be non-null since almost replies are prevented * if either is null. */ if(geoSpec->in_layout) { *cachePtr = geoSpec ; *allowed = *(geoSpec->in_layout) ; } else /* For fixing OSF CR 5956 */ { allowed = NULL ; *cachePtr = NULL ; result = XtGeometryNo ; } break ; } case XtGeometryYes: { /* This must be a query-only request, or the response would * be XtGeometryYes. Cache this reply if caching is * supported. Otherwise, drop through and free geoSpec. */ if( cachePtr ) { *cachePtr = geoSpec ; break ; } } default: { _XmGeoMatrixFree( geoSpec) ; break ; } } return( result) ; } /**************************************************************** * Handle geometry request for XmRESIZE_ANY resize policy. * Accept request allowed by parent. * Reject request to change both width and height if both * are disallowed by parent, but return almost if one is * allowed. ****************/ static XtGeometryResult QueryAnyPolicy( XmGeoMatrix geoSpec, XtWidgetGeometry *parentRequestRtn ) { Widget wid ; Dimension layoutW ; Dimension layoutH ; XtWidgetGeometry parentResponse ; XtGeometryResult queryResult ; Dimension almostW ; Dimension almostH ; /****************/ wid = geoSpec->composite ; _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ; layoutW = 0 ; layoutH = 0 ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &layoutW, &layoutH) ; /* Load request. */ parentRequestRtn->request_mode = CWWidth | CWHeight ; parentRequestRtn->width = layoutW ; parentRequestRtn->height = layoutH ; /* Query parent only if necessary. */ if( (layoutW == XtWidth( wid)) && (layoutH == XtHeight( wid)) ) { parentRequestRtn->request_mode = 0 ; queryResult = XtGeometryYes ; } else { parentRequestRtn->request_mode |= XtCWQueryOnly ; queryResult = XtMakeGeometryRequest( wid, parentRequestRtn, &parentResponse) ; if( queryResult == XtGeometryAlmost ) { if( (parentResponse.request_mode & (CWWidth | CWHeight)) != (CWWidth | CWHeight) ) { queryResult = XtGeometryNo ; } else { /* The protocol guarantees an XtGeometryYes reply for * for an immediately subsequent request which is * identical to the XtGeometryAlmost reply. */ *parentRequestRtn = parentResponse ; queryResult = XtGeometryYes ; almostW = parentResponse.width ; almostH = parentResponse.height ; if( (almostW != layoutW) || (almostH != layoutH) ) { /* Response to geometry request was different than * requested geometry in fields that we care about. * So, try a new arrangement with the area being * offered by the parent. */ _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ; layoutW = almostW ; layoutH = almostH ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &layoutW, &layoutH) ; if( (almostW != layoutW) || (almostH != layoutH) ) { /* The children cannot be laid-out in the area offered * by the parent, so parent result is No. */ queryResult = XtGeometryNo ; } } } } } return( queryResult) ; } /**************************************************************** * Handle geometry request for XmRESIZE_GROW resize policy. * Accept request which would increase or maintain current size. * Reject request which would decrease both preferred width * and preferred height, but return almost if only one * would decrease. ****************/ static XtGeometryResult QueryGrowPolicy( XmGeoMatrix geoSpec, XtWidgetGeometry *parentRequestRtn ) { Widget wid ; Dimension layoutW ; Dimension layoutH ; XtWidgetGeometry parentResponse ; XtGeometryResult queryResult ; Dimension almostW ; Dimension almostH ; /****************/ wid = geoSpec->composite ; _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ; if( geoSpec->instig_request.request_mode & CWWidth ) { layoutW = 0 ; /* Let the layout routine choose a width.*/ } else { layoutW = XtWidth( wid) ; /* All changes will be reflected in */ } /* vertical dimension. */ layoutH = XtHeight( wid) ; /* Layout routine will grow vert., if needed.*/ _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &layoutW, &layoutH) ; if( layoutW < XtWidth( wid) ) { /* Try again, this time passing the width to _XmGeoArrangeBoxes. */ _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ; layoutW = XtWidth( wid) ; layoutH = XtHeight( wid) ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &layoutW, &layoutH) ; } /* Load request. */ parentRequestRtn->request_mode = CWWidth | CWHeight ; parentRequestRtn->width = layoutW ; parentRequestRtn->height = layoutH ; /* Query parent only if necessary. */ if( (layoutW == XtWidth( wid)) && (layoutH == XtHeight( wid)) ) { parentRequestRtn->request_mode = 0 ; queryResult = XtGeometryYes ; } else { parentRequestRtn->request_mode |= XtCWQueryOnly ; queryResult = XtMakeGeometryRequest( wid, parentRequestRtn, &parentResponse) ; if( queryResult == XtGeometryAlmost ) { if( (parentResponse.request_mode & (CWWidth | CWHeight)) != (CWWidth | CWHeight) ) { queryResult = XtGeometryNo ; } else { /* The protocol guarantees an XtGeometryYes reply for * for an immediately subsequent request which is * identical to the XtGeometryAlmost reply. */ *parentRequestRtn = parentResponse ; queryResult = XtGeometryYes ; almostW = parentResponse.width ; almostH = parentResponse.height ; if( (almostW < XtWidth( wid)) || (almostH < XtHeight( wid)) ) { queryResult = XtGeometryNo ; } else { if( (almostW != layoutW) || (almostH != layoutH) ) { /* Response to geometry request was different than * requested geometry in fields that we care about. * So, try a new arrangement with the area being * offered by the parent. */ _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ; layoutW = almostW ; layoutH = almostH ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &layoutW, &layoutH) ; if( (almostW != layoutW) || (almostH != layoutH) ) { /* The children cannot be laid-out in the area * offered by the parent, so parent result is No. */ queryResult = XtGeometryNo ; } } } } } } return( queryResult) ; } /**************************************************************** * Handle geometry request for XmRESIZE_NONE resize policy. * Accept request which would not change preferred size and * allowed by parent. * Reject request which would change both preferred width * and preferred height, but return almost if only one * would change and parent allows the other. ****************/ static XtGeometryResult QueryNonePolicy( XmGeoMatrix geoSpec, XtWidgetGeometry *parentRequestRtn ) { Widget wid ; Dimension layoutW ; Dimension layoutH ; /****************/ wid = geoSpec->composite ; _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ; layoutW = XtWidth( wid) ; layoutH = XtHeight( wid) ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &layoutW, &layoutH) ; parentRequestRtn->request_mode = 0 ; if( (layoutW != XtWidth( wid)) || (layoutH != XtHeight( wid)) ) { return( XtGeometryNo) ; } return( XtGeometryYes) ; } /****************************************************************/ void _XmHandleSizeUpdate( Widget wid, #if NeedWidePrototypes unsigned int policy, #else unsigned char policy, #endif /* NeedWidePrototypes */ XmGeoCreateProc createMatrix) { XmGeoMatrix geoSpec ; Dimension w ; Dimension h ; Dimension r_w ; Dimension r_h ; XtGeometryResult parentResult = XtGeometryNo ; /****************/ geoSpec = (*createMatrix)( wid, NULL, NULL) ; _XmGeoMatrixGet( geoSpec, XmGET_PREFERRED_SIZE) ; switch( policy ) { case XmRESIZE_NONE: { w = XtWidth( wid) ; h = XtHeight( wid) ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &w, &h) ; break ; } case XmRESIZE_GROW: { w = 0 ; h = XtHeight( wid) ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &w, &h) ; if( w < XtWidth( wid) ) { w = XtWidth( wid) ; h = XtHeight( wid) ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &w, &h) ; } break ; } case XmRESIZE_ANY: default: { w = 0 ; h = 0 ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &w, &h) ; break ; } } if( ((w == XtWidth( wid)) && (h == XtHeight( wid))) ) { parentResult = XtGeometryYes ; } else { if( policy != XmRESIZE_NONE ) { parentResult = XtMakeResizeRequest( wid, w, h, &r_w, &r_h) ; if( parentResult == XtGeometryAlmost ) { if( (policy == XmRESIZE_GROW) && ( (r_w < XtWidth( wid)) || (r_h < XtHeight( wid))) ) { parentResult = XtGeometryNo ; } else { w = r_w ; h = r_h ; _XmGeoArrangeBoxes( geoSpec, (Position) 0, (Position) 0, &w, &h) ; if( (w == r_w) && (h == r_h) ) { XtMakeResizeRequest( wid, w, h, NULL, NULL) ; } else { parentResult = XtGeometryNo ; } } } } } if( parentResult != XtGeometryNo ) { _XmGeoMatrixSet( geoSpec) ; } _XmGeoMatrixFree( geoSpec) ; return ; } /**************************************************************** * This routine allocates and initializes the data structure used * to describe a matrix of geometry boxes. Supplemental initialization * may be required for some of the fields of the data structure, if * the user uses these fields in its supplied co-routines. * Rows of the GeoMatrix are lists of kid boxes which are terminated with * a NULL in the kid widget field of the box structure. This routine * automatically allocates extra boxes to use to mark the end of each * row list. * This routine initializes all fields to NULL. * The pointer returned by this routine should be freed by the user * using the _XmGeoMatrixFree() routine. ****************/ XmGeoMatrix _XmGeoMatrixAlloc( unsigned int numRows, /* Number of rows of widgets to layout.*/ unsigned int numBoxes, /* Total number of widgets of matrix.*/ unsigned int extSize ) /* Extension record size (bytes).*/ { XmGeoMatrix geoSpecPtr ; unsigned int matrixRecSize ; unsigned int layoutRecSize ; unsigned int kidGeoRecSize ; unsigned int layoutSize ; unsigned int boxesSize ; unsigned int totalSize ; /****************/ /* Get sizes of the various components of the GeoMatrix. Round up to * prevent alignment problems. */ matrixRecSize = sizeof( XmGeoMatrixRec) ; if( matrixRecSize & 0x03 ) { matrixRecSize = (matrixRecSize + 4) & ~((unsigned int) 0x03) ; } layoutRecSize = sizeof( XmGeoRowLayoutRec) ; if( layoutRecSize & 0x03 ) { layoutRecSize = (layoutRecSize + 4) & ~((unsigned int) 0x03) ; } kidGeoRecSize = sizeof( XmKidGeometryRec) ; if( kidGeoRecSize & 0x03 ) { kidGeoRecSize = (kidGeoRecSize + 4) & ~((unsigned int) 0x03) ; } layoutSize = (numRows + 1) * layoutRecSize ; /* Extra boxes are used to mark the end of each row. */ boxesSize = (numBoxes + numRows) * kidGeoRecSize ; totalSize = matrixRecSize + layoutSize + boxesSize + extSize ; geoSpecPtr = (XmGeoMatrix) XtCalloc( 1, totalSize) ; /* Must be zeroed.*/ /* Set locations of arrays of row layout, box, and extension records. */ geoSpecPtr->layouts = (XmGeoMajorLayout) (((char *) geoSpecPtr) + matrixRecSize) ; geoSpecPtr->boxes = (XmKidGeometry) (((char *) geoSpecPtr) + matrixRecSize + layoutSize) ; if( extSize ) { geoSpecPtr->extension = (XtPointer) (((char *) geoSpecPtr) + matrixRecSize + layoutSize + boxesSize) ; } return( geoSpecPtr) ; } void _XmGeoMatrixFree( XmGeoMatrix geo_spec) { if( geo_spec->ext_destructor ) { (*(geo_spec->ext_destructor))( geo_spec->extension) ; } XtFree( (char *) geo_spec) ; } /**************************************************************** * If the widget specified by the "kidWid" parameter is non-NULL and is managed, * its value is copied into the appropriate field of the kid geometry * structure provided by the "geo" parameter and TRUE is returned. * Otherwise, nothing is done and FALSE is returned. ****************/ Boolean _XmGeoSetupKid( XmKidGeometry geo, /* Must be non-NULL.*/ Widget kidWid ) { /****************/ if( !kidWid || !XtIsManaged( kidWid) ) { return( FALSE) ; } /* The widget ID will be used for subsequent "get" operation. */ geo->kid = (Widget) kidWid; /* Return TRUE so the user knows that the box record was filled with * a widget ID and can then increment the box pointer for the next * managed widget to be setup. */ return( TRUE) ; } /**************************************************************** * This routine goes through the widget matrix and retrieves the appropriate * values for the KidGeometry boxes. Field values of the boxes may be * altered according to requirements specified in each row structure of * the geoSpec. * If the widget id within the matrix matches the instigator field of the * geoSpec, then the value for the box is taken from the request field of * the geoSpec or the widget itself as appropriate. ****************/ void _XmGeoMatrixGet( XmGeoMatrix geoSpec, int geoType ) /* XmGET_PREFERRED_SIZE or */ { register XmKidGeometry boxPtr ; XmKidGeometry rowPtr ; XmGeoRowLayout layoutPtr ; XtWidgetGeometry * request ; Widget instigator ; /****************/ request = &geoSpec->instig_request ; instigator = geoSpec->instigator ; rowPtr = geoSpec->boxes ; layoutPtr = &(geoSpec->layouts->row) ; while( !(layoutPtr->end) ) { boxPtr = rowPtr ; while( boxPtr->kid ) { _XmGeoLoadValues( boxPtr->kid, geoType, instigator, request, &(boxPtr->box)) ; if( boxPtr->kid == instigator ) { geoSpec->in_layout = &(boxPtr->box) ; } ++boxPtr ; } if( layoutPtr->fix_up ) { (*(layoutPtr->fix_up))( geoSpec, geoType, (XmGeoMajorLayout) layoutPtr, rowPtr) ; } rowPtr = boxPtr + 1 ; /* Skip over NULL box marking the end of row.*/ ++layoutPtr ; /* Go to next row layout record.*/ } #ifdef DEBUG_GEOUTILS PrintMatrix( "(get) ", geoSpec) ; #endif return ; } /**************************************************************** * The XtConfigureWidget routine is called on all widgets of the geoSpec * matrix as needed (when the geometry values of the box have changed). * If a widget ID matches that of the instigator field of the geoSpec, * then that widget is not configured. * Any layout "fixup" routines which are specified in the row structure * of the geoSpec are called before and after the call * to XmeConfigureObject, with appropriate parameter values. ****************/ void _XmGeoMatrixSet( XmGeoMatrix geoSpec ) { register XmKidGeometry rowPtr ; register XmGeoRowLayout layoutPtr ; Boolean fixUps = FALSE ; /****************/ #ifdef DEBUG_GEOUTILS PrintMatrix( "(set) ", geoSpec) ; #endif /* Give the user a chance to avoid setting the widgets to box values. */ if( !geoSpec->set_except || !(*geoSpec->set_except)( geoSpec) ) { /* Give the user a chance to modify box sizes before setting * the widget to the values defined in the box record. */ layoutPtr = &(geoSpec->layouts->row) ; rowPtr = geoSpec->boxes ; while( !(layoutPtr->end) ) { if( layoutPtr->fix_up ) { /* Call the user's routine which may modify boxes of this row. */ (*(layoutPtr->fix_up))( geoSpec, XmGEO_PRE_SET, (XmGeoMajorLayout) layoutPtr, rowPtr) ; fixUps = TRUE ; } rowPtr += layoutPtr->box_count + 1 ; /* Skip to next row.*/ ++layoutPtr ; } /* Now set the widgets to the values in the boxes. */ layoutPtr = &(geoSpec->layouts->row) ; rowPtr = geoSpec->boxes ; while( !(layoutPtr->end) ) { _XmSetKidGeo( rowPtr, geoSpec->instigator) ; rowPtr += layoutPtr->box_count + 1 ; /* Skip to next row.*/ ++layoutPtr ; } if( fixUps ) { /* Now call the fix_up routines again, to give the user a chance to * undo the chances to the boxes in order to keep consistency for * subsequent layout operations. */ layoutPtr = &(geoSpec->layouts->row) ; rowPtr = geoSpec->boxes ; while( !(layoutPtr->end) ) { if( layoutPtr->fix_up ) { (*(layoutPtr->fix_up))( geoSpec, XmGEO_POST_SET, (XmGeoMajorLayout) layoutPtr, rowPtr) ; } rowPtr += layoutPtr->box_count + 1 ; /* Skip to next row.*/ ++layoutPtr ; } } } return ; } /**************************************************************** * This routine adjusts boxes according to policies regarding border size * and even-sized boxes. Box dimensions are altered appropriately if * even_width or even_height parameters are set. Borders are set if * uniform_border is TRUE. ****************/ void _XmGeoAdjustBoxes( XmGeoMatrix geoSpec ) { register XmKidGeometry rowPtr ; register XmKidGeometry boxPtr ; XmGeoRowLayout layoutPtr ; Dimension globalSetBorder ; Dimension globalBorder ; Dimension borderValue ; /****************/ globalSetBorder = geoSpec->uniform_border ; globalBorder = geoSpec->border ; rowPtr = geoSpec->boxes ; layoutPtr = &(geoSpec->layouts->row) ; while( !(layoutPtr->end) ) { if( layoutPtr->even_width ) { _XmGeoBoxesSameWidth( rowPtr, layoutPtr->even_width) ; } if( layoutPtr->even_height ) { _XmGeoBoxesSameHeight( rowPtr, layoutPtr->even_height) ; } if( globalSetBorder || layoutPtr->uniform_border ) { if( globalSetBorder ) { borderValue = globalBorder ; } else { borderValue = layoutPtr->border ; } boxPtr = rowPtr ; while( boxPtr->kid ) { boxPtr->box.border_width = borderValue ; ++boxPtr ; } } while( (rowPtr++)->kid ) /* Go to next row of boxes. */ { /*EMPTY*/ } ++layoutPtr ; /* Go to next row layout record.*/ } return ; } /**************************************************************** * This routine traverses the matrix and collects data regarding the * sizes of boxes, the minimum fill area expected, and various other * parameters which are used during the layout process. ****************/ void _XmGeoGetDimensions( XmGeoMatrix geoSpec ) { register XmKidGeometry rowPtr ; register XmKidGeometry boxPtr ; XmGeoRowLayout layoutPtr ; Dimension boxH ; Dimension rowH ; Dimension rowW ; Dimension matrixFillH ; Dimension matrixBoxesH ; Dimension matrixW ; Dimension endSpaceW ; unsigned int numBoxes ; Dimension marginW ; Dimension marginH ; /****************/ marginH = geoSpec->margin_h ; marginW = geoSpec->margin_w ; rowPtr = geoSpec->boxes ; layoutPtr = &(geoSpec->layouts->row) ; matrixW = 0 ; matrixBoxesH = 0 ; matrixFillH = layoutPtr->space_above ; if( matrixFillH < marginH ) { matrixFillH = 0 ; } else { matrixFillH -= marginH ; /* This dimension does not include margins.*/ } geoSpec->stretch_boxes = FALSE ; while( !(layoutPtr->end) ) { /* Gather information about the height, width, and number of boxes * in the row. */ rowW = 0 ; rowH = 0 ; numBoxes = 0 ; boxPtr = rowPtr ; while( boxPtr->kid ) { rowW += boxPtr->box.width + (boxPtr->box.border_width << 1) ; boxH = boxPtr->box.height + (boxPtr->box.border_width << 1) ; ASSIGN_MAX( rowH, boxH) ; /* The tallest box is the row height.*/ ++numBoxes ; ++boxPtr ; } /* Fill row layout record with info about row. */ layoutPtr->max_box_height = rowH ;/* Tallest box in row, with border.*/ layoutPtr->boxes_width = rowW ; /* Sum of box widths and borders.*/ layoutPtr->box_count = numBoxes ; /* Check for vertical stetch row. */ if( layoutPtr->stretch_height ) { if( layoutPtr->fit_mode != XmGEO_WRAP ) { geoSpec->stretch_boxes = TRUE ; } else { layoutPtr->stretch_height = FALSE ; } } /* Compute row width to generate matrix width. Exclude margins. */ if( layoutPtr->space_end > marginW ) { endSpaceW = layoutPtr->space_end - marginW ; } else { endSpaceW = 0 ; } /* Fill width is the minimum spacing between (borders of) boxes plus * any extra space required at ends. Margins are not included. */ layoutPtr->fill_width = (endSpaceW << 1) + ((numBoxes - 1) * layoutPtr->space_between) ; /* Maximum row width is the overall matrix width, less margins. Add * box width to fill width for total width this row. */ rowW += layoutPtr->fill_width ; ASSIGN_MAX( matrixW, rowW) ; rowPtr = boxPtr + 1 ; /* Skip over NULL box marking the end of row.*/ ++layoutPtr ; /* Go to next row layout record.*/ /* Accumulate heights of each row. */ matrixFillH += layoutPtr->space_above ; matrixBoxesH += rowH ; } /* The matrixFillH variable already has fill space included from the final * row layout record. This must be reduced by the amount of the margin, * or a smaller amount if the amount specified was less than the margin. */ if( layoutPtr->space_above < marginH ) { matrixFillH -= layoutPtr->space_above ; } else { matrixFillH -= marginH ; } geoSpec->max_major = matrixW ; /* Widest row, excluding margins. */ geoSpec->boxes_minor = matrixBoxesH ; /* Sum of tallest box in each row.*/ geoSpec->fill_minor = matrixFillH ; /* Sum of vertical fill spacing. */ } /**************************************************************** * After the boxes have been layed-out according to the minimum vertical fill * requirements of the matrix, this routine stretches the layout to fill * any extra space required by the managing widget. * Returns new height after extra spacing is inserted. ****************/ static Dimension _XmGeoStretchVertical( XmGeoMatrix geoSpec, #if NeedWidePrototypes int actualH, int desiredH ) #else Dimension actualH, Dimension desiredH ) #endif /* NeedWidePrototypes */ { register XmGeoRowLayout layoutPtr ; register XmKidGeometry rowPtr ; int fillOffset ; int stretchableSpace ; int deltaY ; int deltaH ; /****************/ layoutPtr = &(geoSpec->layouts->row) ; stretchableSpace = 0 ; fillOffset = ((int) desiredH) - ((int) actualH) ; if( fillOffset < 0 ) { /* Must shrink stretchable boxes. */ while( !layoutPtr->end ) { if( layoutPtr->stretch_height && (layoutPtr->max_box_height > layoutPtr->min_height) ) { stretchableSpace += layoutPtr->max_box_height - layoutPtr->min_height ; } ++layoutPtr ; } if( -fillOffset > stretchableSpace ) { fillOffset = -stretchableSpace ; } } else { /* Must grow stretchable boxes. */ while( !layoutPtr->end ) { if( layoutPtr->stretch_height ) { stretchableSpace += layoutPtr->max_box_height ; } ++layoutPtr ; } } if( !stretchableSpace ) { /* No stretchable boxes, so return with current height. */ return( actualH) ; } deltaY = 0 ; rowPtr = geoSpec->boxes ; layoutPtr = &(geoSpec->layouts->row) ; while( !layoutPtr->end ) { if( layoutPtr->stretch_height ) { if( fillOffset < 0 ) { if( layoutPtr->max_box_height > layoutPtr->min_height ) { deltaH = (((int) (layoutPtr->max_box_height - layoutPtr->min_height)) * fillOffset) / stretchableSpace ; } else { deltaH = 0 ; } /* deltaH is now <= 0. */ while( rowPtr->kid ) { int boxCorrection = layoutPtr->max_box_height - rowPtr->box.height ; if( boxCorrection > -deltaH ) { boxCorrection = -deltaH ; } rowPtr->box.height += deltaH + boxCorrection ; rowPtr->box.y += deltaY - (boxCorrection >> 1) ; ++rowPtr ; } } else /* fillOffset >= 0 */ { deltaH = (layoutPtr->max_box_height * fillOffset) / stretchableSpace ; while( rowPtr->kid ) { rowPtr->box.height += deltaH ; rowPtr->box.y += deltaY ; ++rowPtr ; } } deltaY += deltaH ; } else { while( rowPtr->kid ) { rowPtr->box.y += deltaY ; ++rowPtr ; } } ++rowPtr ; ++layoutPtr ; } return( actualH + deltaY) ; /* Return new height.*/ } /**************************************************************** * After the boxes have been layed-out according to the minimum vertical fill * requirements of the matrix, this routine stretches the layout to fill * any extra space required by the managing widget. * Returns new height after extra spacing is inserted. ****************/ static Dimension _XmGeoFillVertical( XmGeoMatrix geoSpec, #if NeedWidePrototypes int actualH, int desiredH ) #else Dimension actualH, Dimension desiredH ) #endif /* NeedWidePrototypes */ { register XmGeoRowLayout layoutPtr ; register XmKidGeometry rowPtr ; unsigned long fillAmount ; unsigned long totalSpecSpace ; Dimension marginH ; Dimension firstSpecSpace ; Dimension lastSpecSpace ; Dimension currentFirstSpace ; Dimension currentLastSpace ; Dimension newFirstSpace ; Dimension newLastSpace ; int deltaY ; /****************/ /* Need to accumulate specified spacing factors, saving first and last * ends separately. */ layoutPtr = &(geoSpec->layouts->row) ; totalSpecSpace = 0 ; firstSpecSpace = layoutPtr->space_above ; while( !(++layoutPtr)->end ) { totalSpecSpace += layoutPtr->space_above ; } lastSpecSpace = layoutPtr->space_above ; totalSpecSpace += firstSpecSpace + lastSpecSpace ; if( !totalSpecSpace ) { /* Zero spacing specified, so just return as is. */ return( actualH) ; } /* Must reconstruct the actual spacing, which is the specified minimum. * Save current end spacing separately, since everything done here is * relative to the actual coordinates of the matrix and it will be * needed later. */ marginH = geoSpec->margin_h ; currentFirstSpace = (firstSpecSpace < marginH) ? marginH : firstSpecSpace ; currentLastSpace = (lastSpecSpace < marginH) ? marginH : lastSpecSpace ; /* Fill amount includes the current fill plus margins and extra * spacing. */ fillAmount = (desiredH - actualH) + geoSpec->fill_minor + currentFirstSpace + currentLastSpace ; newFirstSpace = (Dimension) ((fillAmount * (unsigned long) firstSpecSpace) / totalSpecSpace) ; newLastSpace = (Dimension) ((fillAmount * (unsigned long) lastSpecSpace) / totalSpecSpace) ; if( newFirstSpace < marginH ) { fillAmount -= marginH ; totalSpecSpace -= firstSpecSpace ; newFirstSpace = marginH ; } if( newLastSpace < marginH ) { fillAmount -= marginH ; totalSpecSpace -= lastSpecSpace ; newLastSpace = marginH ; } /* Now traverse the matrix, offsetting all y-ccordinates according to * additional spacing. Wrapped lines receive no extra spacing between * them. */ deltaY = newFirstSpace - currentFirstSpace ; rowPtr = geoSpec->boxes ; layoutPtr = &(geoSpec->layouts->row) ; for(;;) { while( rowPtr->kid ) { rowPtr->box.y += deltaY ; ++rowPtr ; } ++rowPtr ; ++layoutPtr ; if( layoutPtr->end ) { break ; } deltaY += (int) (((((unsigned long) layoutPtr->space_above) * fillAmount) / totalSpecSpace) - layoutPtr->space_above) ; } deltaY += newLastSpace - currentLastSpace ; return( actualH + deltaY) ; /* Return new height.*/ } /**************************************************************** * Calculates and returns appropriate fill factor from given layout * parameters. Also returns appropriate spacing for ends. * The fill factor returned is for use with all spacing between boxes, but * not the ends (use provided spacing). ****************/ static void _XmGeoCalcFill( #if NeedWidePrototypes int fillSpace, int margin, #else Dimension fillSpace, /* Fill space, including margins.*/ Dimension margin, /* Margin (included in fillSpace).*/ #endif /* NeedWidePrototypes */ unsigned int numBoxes, #if NeedWidePrototypes int endSpec, int betweenSpec, #else Dimension endSpec, Dimension betweenSpec, #endif /* NeedWidePrototypes */ Dimension *pEndSpace, /* Receives end spacing.*/ Dimension *pBetweenSpace ) /* Receives between spacing.*/ { Dimension totalSpecSpace ;/* Sum of specified spacing.*/ /****************/ if( !endSpec ) { if( numBoxes == 1 ) { endSpec = 1 ; } else { if( !betweenSpec ) { betweenSpec = (Dimension) (numBoxes - 1) ; } } } totalSpecSpace = (betweenSpec * (numBoxes - 1)) + (endSpec << 1) ; *pEndSpace = (endSpec * fillSpace) / totalSpecSpace ; if( *pEndSpace < margin ) { if( (endSpec << 1) < totalSpecSpace ) { totalSpecSpace -= endSpec << 1 ; } else { totalSpecSpace = 1 ; } if( (margin << 1) < fillSpace ) { fillSpace -= margin << 1 ; } else { fillSpace = 0 ; } *pEndSpace = margin ; } *pBetweenSpace = (betweenSpec * fillSpace) / totalSpecSpace ; return ; } /**************************************************************** * The x, y, width, and height fields of the boxes in the geoSpec matrix * are modified with values appropriate for the layout parameters specified * by x, y, pW, and pH. * The overall width and height dimensions at the specified locations * of pW and pH must be initially set to their desired values, or zero * for the default layout. * The actual values of the width and height (after layout) are returned at * the locations pW and pH. ****************/ void _XmGeoArrangeBoxes( XmGeoMatrix geoSpec, /* Array of box lists (rows).*/ #if NeedWidePrototypes int x, int y, #else Position x, /* X coordinate of composite.*/ Position y, /* Y coordinate of composite.*/ #endif /* NeedWidePrototypes */ Dimension *pW, /* Initial value is minimum width.*/ Dimension *pH ) /* Initial value is minimum height.*/ { Dimension marginW ; /* Margin between sides and boxes.*/ Dimension marginH ; /* Margin between top/bot and boxes.*/ XmKidGeometry rowPtr ; XmGeoRowLayout layoutPtr ; Dimension actualW ; Dimension actualH ; Dimension initY ; /****************/ if( geoSpec->arrange_boxes && (geoSpec->arrange_boxes != _XmGeoArrangeBoxes) ) { (*(geoSpec->arrange_boxes))( geoSpec, x, y, pW, pH) ; return ; } /* Fix box dimensions according to even_height/width and uniform_border * specifications. */ _XmGeoAdjustBoxes( geoSpec) ; /* Compute layout dimensions. */ _XmGeoGetDimensions( geoSpec) ; /* Initialize global layout dimensions. */ marginW = geoSpec->margin_w ; marginH = geoSpec->margin_h ; actualW = geoSpec->max_major + (marginW << 1) ; /****** the value of this assignment is never used ********** actualH = geoSpec->boxes_minor + geoSpec->fill_minor + (marginH << 1) ; *************************************************************/ /* Adjust layout dimensions to requested dimensions. */ if( *pW ) { actualW = *pW ; } /******* the value assigned to actualH is never used ************* if( *pH ) { actualH = *pH ; } ******************************************************************/ /* Save initial Y coordinate for later computation of height. */ initY = y ; /* Layout horizontal position of each box in row, one row at a time. */ layoutPtr = &(geoSpec->layouts->row) ; rowPtr = geoSpec->boxes ; /* Add first end spacing. */ if( layoutPtr->space_above > marginH ) { y += layoutPtr->space_above ; } else { y += marginH ; } while( !(layoutPtr->end) ) { /* Arrange one row of boxes at a time. */ y = _XmGeoArrangeList( rowPtr, layoutPtr, x, y, actualW, marginW, marginH) ; rowPtr += layoutPtr->box_count + 1 ; /* Skip to next row.*/ ++layoutPtr ; /* Add between-row spacing. */ y += layoutPtr->space_above ; } if( layoutPtr->space_above < marginH ) { /* Fill out to the minimum margin if previous spacing is less * than margin. */ y += marginH - layoutPtr->space_above ; } actualH = y - initY ; if( *pH && (actualH != *pH) ) { if( geoSpec->stretch_boxes ) { /* Has stretchable boxes, so grow or shrink using stretch. */ actualH = _XmGeoStretchVertical( geoSpec, actualH, *pH) ; } else { if( actualH < *pH ) { /* Layout is smaller than specified height, so fill vertically. */ actualH = _XmGeoFillVertical( geoSpec, actualH, *pH) ; } } } /* Set return values of actual width and height of matrix. */ geoSpec->width = actualW ; if( *pW < actualW ) { *pW = actualW ; } geoSpec->height = actualH ; if( *pH < actualH ) { *pH = actualH ; } return ; } /****************************************************************/ static int boxWidthCompare( XmConst void * boxPtr1, XmConst void * boxPtr2 ) { /****************/ return( (*((XmKidGeometry *) boxPtr1))->box.width > (*((XmKidGeometry *) boxPtr2))->box.width) ; } /**************************************************************** * This routine alters box sizes such that the composite width is reduced * by the offset amount specified. The boxWidth parameter is assumed to * contain the sum of the all box widths, including borders. * The algorithm used by this routine tends to average the width of all boxes. * In other words, to achieve the desired width reduction, the largest boxes * are reduced first, possibly until all boxes are the same width * (thereafter reducing all boxes evenly). ****************/ static void FitBoxesAveraging( XmKidGeometry rowPtr, unsigned int numBoxes, #if NeedWidePrototypes int boxWidth, #else Dimension boxWidth, #endif /* NeedWidePrototypes */ int amtOffset ) { unsigned int Index ; XmKidGeometry * sortedBoxes ; /****************/ /* Get memory to use for sorting the list of boxes. */ sortedBoxes = (XmKidGeometry *) XtMalloc( numBoxes * sizeof( XmKidGeometry)) ; /* Enter the boxes into the array and sort. */ Index = 0 ; while( Index < numBoxes ) { sortedBoxes[Index] = &rowPtr[Index] ; /* Need to remove the border_width component from boxWidth. */ boxWidth -= (rowPtr[Index].box.border_width << 1) ; ++Index ; } qsort( (void *) sortedBoxes, (size_t) numBoxes, sizeof( XmKidGeometry), boxWidthCompare) ; /* Now sorted with smallest box first. */ Index = 0 ; while( Index < numBoxes ) { /* The right-hand side of the comparison represents the amount of * area that would be truncated if all boxes were the same width * as sortedBoxes[Index]. The loop will break when the Index * points to the smallest box in the list to be truncated. */ if( amtOffset >= ((int) (boxWidth - ((sortedBoxes[Index]->box.width) * (numBoxes - Index)))) ) { break ; } /* This keeps the above comparison simple. */ boxWidth -= sortedBoxes[Index]->box.width ; ++Index ; } if( Index < numBoxes ) { if( (int) boxWidth > amtOffset ) { boxWidth = (boxWidth - amtOffset) / (numBoxes - Index) ; if( !boxWidth ) { boxWidth = 1 ; } } else { boxWidth = 1 ; } /* boxWidth is now the truncated width of the remaining boxes * in the sorted list. Set these boxes appropriately. */ while( Index < numBoxes ) { sortedBoxes[Index]->box.width = boxWidth ; ++Index ; } } XtFree( (char *) sortedBoxes) ; return ; } /**************************************************************** * This routine alters the width of boxes in proportion to the width of each * box such that the total change is equal to amtOffset. If amtOffset is * greater than zero, the total width is reduced (a "fit"). Otherwise, * the total width is increased (a "fill"). ****************/ static void FitBoxesProportional( XmKidGeometry rowPtr, unsigned int numBoxes, #if NeedWidePrototypes int boxWidth, #else Dimension boxWidth, #endif /* NeedWidePrototypes */ int amtOffset ) { int deltaX ; int deltaW ; /****************/ if( boxWidth >= numBoxes ) { deltaX = 0 ; while( rowPtr->kid ) { deltaW = (amtOffset * (int)(rowPtr->box.width + (rowPtr->box.border_width << 1))) / ((int) boxWidth) ; if( deltaW < ((int) rowPtr->box.width) ) { rowPtr->box.width -= deltaW ; } else { rowPtr->box.width = 1 ; } rowPtr->box.x += deltaX ; deltaX -= deltaW ; ++rowPtr ; } } else /* boxWidth < numBoxes */ { if( (-amtOffset) > numBoxes ) { boxWidth = (-amtOffset) / numBoxes ; } else { boxWidth = 1 ; } deltaX = 0 ; while( rowPtr->kid ) { rowPtr->box.width = boxWidth ; rowPtr->box.x += deltaX ; deltaX += boxWidth ; ++rowPtr ; } } return ; } /****************************************************************/ static void SegmentFill( XmKidGeometry rowBoxes, unsigned int numBoxes, XmGeoRowLayout layoutPtr, #if NeedWidePrototypes int x, int width, int marginW, int endX, int maxX, int endSpace, int betweenSpace ) #else Position x, Dimension width, Dimension marginW, Position endX, Position maxX, Dimension endSpace, Dimension betweenSpace ) #endif /* NeedWidePrototypes */ { Widget holdEnd ; Dimension spacedWidth ; Dimension boxWidth ; Dimension sumW ; int amtOffset ; Dimension totalFill ; Position rowX ; XmKidGeometry rowPtr ; /****************/ holdEnd = rowBoxes[numBoxes].kid ; rowBoxes[numBoxes].kid = NULL ; spacedWidth = (betweenSpace * (numBoxes - 1)) + (endSpace << 1) ; amtOffset = ((int) spacedWidth + (maxX - endX)) ; if( (amtOffset > 0) && (amtOffset < width) ) { boxWidth = width - amtOffset ; } else { boxWidth = 1 ; } sumW = boxWidth + spacedWidth ; amtOffset = ((int) sumW) - ((int) width) ; /* Setup the default spacing. */ betweenSpace = layoutPtr->space_between ; endSpace = (layoutPtr->space_end < marginW) ? marginW : layoutPtr->space_end ; switch( layoutPtr->fill_mode ) { case XmGEO_CENTER: { /* Compute new spacing values to result in a centered * layout when passed to the simple layout routine. */ if( width > sumW ) { totalFill = (spacedWidth + width) - sumW ; } else { totalFill = marginW << 1 ; } { /* This little exercise is needed for when NeedWidePrototypes * has value 1 which causes endSpace and betweenSpace to * become "int"s, and a pointer to an int cannot be passed * as an argument where a pointer to a dimension is required. */ Dimension eSpace ; Dimension bSpace ; _XmGeoCalcFill( totalFill, marginW, numBoxes, layoutPtr->space_end, layoutPtr->space_between, &eSpace, &bSpace) ; endSpace = eSpace ; betweenSpace = bSpace ; } break ; } case XmGEO_PACK: { /* For a packed layout, just layout with extra space * at the end of the row. */ break ; } case XmGEO_EXPAND: default: { /* FitBoxesProportional will fill if amtOffset < 0, * as it is here. */ FitBoxesProportional( rowBoxes, numBoxes, boxWidth, amtOffset) ; break ; } } rowX = x + endSpace ; rowPtr = rowBoxes ; while( rowPtr->kid ) { rowPtr->box.x = rowX ; rowX += rowPtr->box.width + (rowPtr->box.border_width << 1) + betweenSpace ; ++rowPtr ; } rowBoxes[numBoxes].kid = holdEnd ; return ; } /**************************************************************** * This routine lays out the row of boxes with the spacing specified in * the endSpace and betweenSpace parameters. If the width of a row * which contains more than one box causes the right edge of the * row to be greater than maxX, then the boxes will wrap to the next * line. * The Y coordinate of the space following the layout is returned. ****************/ static Position _XmGeoLayoutWrap( XmKidGeometry rowPtr, XmGeoRowLayout layoutPtr, #if NeedWidePrototypes int x, int y, int endSpace, int betweenSpace, int maxX, int width, int marginW ) #else Position x, Position y, Dimension endSpace, Dimension betweenSpace, Position maxX, Dimension width, Dimension marginW ) #endif /* NeedWidePrototypes */ { Position rowX ; Dimension rowH ; Position boxMaxX ; unsigned int numBoxes ; Dimension boxH ; int deltaW ; XmKidGeometry rowBegin ; register XmKidGeometry boxPtr ; Position endX ; /****************/ rowX = x + endSpace ; rowH = layoutPtr->max_box_height ; numBoxes = 0 ; rowBegin = rowPtr ; boxPtr = rowPtr ; while( boxPtr->kid ) { boxMaxX = rowX + boxPtr->box.width + (boxPtr->box.border_width << 1) ; if( (boxMaxX > maxX) && numBoxes ) { /* Wrap the line. Also adjust preceding segment according to * fill policy. */ endX = rowX - betweenSpace ; SegmentFill( rowBegin, numBoxes, layoutPtr, x, width, marginW, endX, maxX, endSpace, betweenSpace) ; numBoxes = 0 ; rowX = x + endSpace ; y += rowH ; rowBegin = boxPtr ; boxMaxX = rowX + boxPtr->box.width + (boxPtr->box.border_width << 1) ; } if( boxMaxX > maxX ) { /* Since it wasn't wrapped, there must be only one box in this * segment. It is too wide, so simply truncate it. */ deltaW = ((int) (endSpace + boxMaxX)) - ((int) (maxX + marginW)) ; if( (deltaW < ((int) boxPtr->box.width)) && (deltaW > 0) ) { boxPtr->box.width -= deltaW ; } else { boxPtr->box.width = 1 ; } boxMaxX = rowX + boxPtr->box.width + (boxPtr->box.border_width << 1) ; } boxPtr->box.x = rowX ; boxPtr->box.y = y ; boxH = boxPtr->box.height + (boxPtr->box.border_width << 1) ; if( boxH != rowH ) { /* If box height is not the same as the maximum box height * of the row, then adjust y to center the box in the row. */ boxPtr->box.y += (((int) rowH - (int) boxH) >> 1) ; } rowX = boxMaxX + betweenSpace ; ++numBoxes ; ++boxPtr ; } endX = rowX - betweenSpace ; SegmentFill( rowBegin, numBoxes, layoutPtr, x, width, marginW, endX, maxX, endSpace, betweenSpace) ; if( layoutPtr->sticky_end ) { boxPtr = &rowPtr[layoutPtr->box_count - 1] ; endX = maxX - (boxPtr->box.width + (boxPtr->box.border_width << 1)) ; if( endX > boxPtr->box.x ) { boxPtr->box.x = endX ; } } return( y + rowH) ; } /**************************************************************** * This routine does a simple layout of the boxes in the row. It assumes * that all boxes have been conditioned to fit appropriately with the * spacing specified by the endSpace and betweenSpace parameters. * The Y coordinate of the space following the layout is returned. ****************/ static Position _XmGeoLayoutSimple( XmKidGeometry rowPtr, XmGeoRowLayout layoutPtr, #if NeedWidePrototypes int x, int y, int maxX, int endSpace, int betweenSpace ) #else Position x, Position y, Position maxX, Dimension endSpace, Dimension betweenSpace ) #endif /* NeedWidePrototypes */ { Position rowX ; Position newX ; Dimension rowH ; Dimension boxH ; /****************/ rowH = layoutPtr->max_box_height ; rowX = x + endSpace ; while( rowPtr->kid ) { rowPtr->box.x = rowX ; rowPtr->box.y = y ; boxH = rowPtr->box.height + (rowPtr->box.border_width << 1) ; if( boxH != rowH ) { /* If box height is not the same as the maximum box height * of the row, then adjust y to center the box in the row. */ rowPtr->box.y += ((rowH - boxH) >> 1) ; } rowX += rowPtr->box.width + (rowPtr->box.border_width << 1) + betweenSpace ; ++rowPtr ; } if( layoutPtr->sticky_end ) { --rowPtr ; newX = maxX - (rowPtr->box.width + (rowPtr->box.border_width << 1)) ; if( newX > rowPtr->box.x ) { rowPtr->box.x = newX ; } } return( y + rowH) ; } /**************************************************************** * This routines lays out the boxes in this row according to the specified * paramaters and the policies specified in the layout record at layoutPtr. ****************/ /*ARGSUSED*/ static Position _XmGeoArrangeList( XmKidGeometry rowBoxes, XmGeoRowLayout layoutPtr, #if NeedWidePrototypes int x, int y, int width, int marginW, int marginH ) /* unused */ #else Position x, Position y, Dimension width, Dimension marginW, Dimension marginH ) /* unused */ #endif /* NeedWidePrototypes */ { Dimension sumW ; unsigned int numBoxes ; Dimension betweenBoxes ; Dimension endsOfBoxes ; int amtOffset ; Dimension boxWidth ; Position maxX ; Dimension totalFill ; /****************/ numBoxes = layoutPtr->box_count ; boxWidth = layoutPtr->boxes_width ; sumW = boxWidth + layoutPtr->fill_width + (marginW << 1) ; amtOffset = ((int) sumW) - ((int) width) ; /* Setup the default spacing. */ betweenBoxes = layoutPtr->space_between ; endsOfBoxes = (layoutPtr->space_end < marginW) ? marginW : layoutPtr->space_end ; maxX = x + width - marginW ; if( (sumW > width) && (layoutPtr->fit_mode == XmGEO_WRAP) ) { /* Wrapping is required, so fill routines and other policy decisions * are not needed. Do the layout using the wrap routine and we're * done. */ y = _XmGeoLayoutWrap( rowBoxes, layoutPtr, x, y, endsOfBoxes, betweenBoxes, maxX, width, marginW) ; } else { if( sumW > width ) { switch( layoutPtr->fit_mode ) { case XmGEO_AVERAGING: { FitBoxesAveraging( rowBoxes, numBoxes, boxWidth, amtOffset) ; break ; } case XmGEO_PROPORTIONAL: default: { FitBoxesProportional( rowBoxes, numBoxes, boxWidth, amtOffset) ; } } } else { if( sumW < width ) { switch( layoutPtr->fill_mode ) { case XmGEO_CENTER: { /* Compute new spacing values to result in a centered * layout when passed to the simple layout routine. */ totalFill = (marginW << 1) + layoutPtr->fill_width + width - sumW ; _XmGeoCalcFill( totalFill, marginW, numBoxes, layoutPtr->space_end, layoutPtr->space_between, &endsOfBoxes, &betweenBoxes) ; break ; } case XmGEO_PACK: { /* For a packed layout, just layout with extra space * at the end of the row. */ break ; } case XmGEO_EXPAND: default: { /* FitBoxesProportional will fill if amtOffset < 0, * as it is here. */ FitBoxesProportional( rowBoxes, numBoxes, boxWidth, amtOffset) ; break ; } } } } y = _XmGeoLayoutSimple( rowBoxes, layoutPtr, x, y, maxX, endsOfBoxes, betweenBoxes) ; } return( y) ; } /**************************************************************** * Changes boxes in the kid geometry list to have desired width. * If width > 1, then use the specified width. * If width == 1, then use the width of the widest box. * If width == 0, then do not change the boxes but return the width of * the widest box. * Returns the value of the width actually used. ****************/ Dimension _XmGeoBoxesSameWidth( XmKidGeometry rowPtr, #if NeedWidePrototypes int width ) #else Dimension width ) #endif /* NeedWidePrototypes */ { register XmKidGeometry boxPtr ; register Dimension useW ; /****************/ useW = width ; /* Setup default width of each box in row, as specified.*/ if( width <= 1 ) { /* If user specified width parameter of zero or one, then find the * width of the widest box. */ boxPtr = rowPtr ; while( boxPtr->kid ) { ASSIGN_MAX( useW, boxPtr->box.width) ; ++boxPtr ; } } if( width ) { /* If width parameter is non-zero, then set the boxes appropriately. */ boxPtr = rowPtr ; while( boxPtr->kid ) { boxPtr->box.width = useW ; ++boxPtr ; } } return( useW) ; } /**************************************************************** * Changes boxes in the kid geometry list to have desired height. * If height > 1, then use the specified height. * If height == 1, then use the height of the tallest box. * If height == 0, then do not change the boxes but return the height of * the tallest box. * Returns the value of the height actually used. ****************/ Dimension _XmGeoBoxesSameHeight( XmKidGeometry rowPtr, #if NeedWidePrototypes int height ) #else Dimension height ) #endif /* NeedWidePrototypes */ { register XmKidGeometry boxPtr ; register Dimension useH ; /****************/ useH = height ; /* Setup default height of each box in row, as specified.*/ if( height <= 1 ) { /* If user specified height parameter of zero or one, then find the * height of the tallest box. */ boxPtr = rowPtr ; while( boxPtr->kid ) { ASSIGN_MAX( useH, boxPtr->box.height) ; ++boxPtr ; } } if( height ) { /* If height parameter is non-zero, then set the boxes appropriately. */ boxPtr = rowPtr ; while( boxPtr->kid ) { boxPtr->box.height = useH ; ++boxPtr ; } } return( useH) ; } /**************************************************************** ARGSUSED * This routine is a fixup routine which can be used for rows which consist * of a single separator widget. The effect of this routine is to have * the separator ignore the margin width. ****************/ /*ARGSUSED*/ void _XmSeparatorFix( XmGeoMatrix geoSpec, int action, XmGeoMajorLayout layoutPtr, /* unused */ XmKidGeometry rowPtr ) { register Dimension marginW ; register Dimension twoMarginW ; /****************/ marginW = geoSpec->margin_w ; twoMarginW = (marginW << 1) ; switch( action ) { case XmGEO_PRE_SET: { rowPtr->box.x -= marginW ; rowPtr->box.width += twoMarginW ; break ; } default: { if( rowPtr->box.width > twoMarginW ) { /* Avoid subtracting a margin from box width which would * result in underflow. */ rowPtr->box.x += marginW ; rowPtr->box.width -= twoMarginW ; } if( action == XmGET_PREFERRED_SIZE ) { /* Set width to some small value so it does not * effect total width of matrix. */ rowPtr->box.width = 1 ; } break ; } } return ; } /**************************************************************** ARGSUSED * This routine is a fixup routine which can be used for rows which consist * of a single MenuBar RowColumn. The effect of this routine is to have * the RowColumn ignore the margin width and height. ****************/ /*ARGSUSED*/ void _XmMenuBarFix( XmGeoMatrix geoSpec, int action, XmGeoMajorLayout layoutPtr, /* unused */ XmKidGeometry rowPtr ) { register Dimension marginW ; register Dimension marginH ; register Dimension twoMarginW ; /****************/ marginW = geoSpec->margin_w ; twoMarginW = (marginW << 1) ; marginH = geoSpec->margin_h ; switch( action ) { case XmGEO_PRE_SET: { rowPtr->box.x -= marginW ; rowPtr->box.width += twoMarginW ; rowPtr->box.y -= marginH ; break ; } default: { if( rowPtr->box.width > twoMarginW ) { /* Avoid subtracting a margin from box width which would * result in underflow. */ rowPtr->box.x += marginW ; rowPtr->box.width -= twoMarginW ; } if( action == XmGET_PREFERRED_SIZE ) { /* Set width to some small value so it does not * effect total width of matrix. */ rowPtr->box.width = 1 ; } break ; } } return ; } /****************************************************************/ void _XmGeoLoadValues( Widget wid, int geoType, Widget instigator, XtWidgetGeometry *request, XtWidgetGeometry *geoResult ) { XtWidgetGeometry reply ; XtWidgetGeometry * geoSource ; /****************/ if( wid == instigator ) { /* If this widget is making the request, then use the request info. */ geoSource = request ; } else { geoSource = &reply ; switch( geoType ) { case XmGET_PREFERRED_SIZE: { XtQueryGeometry( wid, NULL, &reply) ; break ; } case XmGET_ACTUAL_SIZE: default: { reply.request_mode = 0 ; /* Will cause geoSpec to be loaded.*/ break ; } } } geoResult->x = IsX( geoSource) ? geoSource->x : XtX( wid) ; geoResult->y = IsY( geoSource) ? geoSource->y : XtY( wid) ; geoResult->width = IsWidth( geoSource) ? geoSource->width : XtWidth( wid) ; geoResult->height = IsHeight( geoSource) ? geoSource->height : XtHeight( wid) ; geoResult->border_width = IsBorder( geoSource) ? geoSource->border_width : XtBorderWidth( wid) ; geoResult->request_mode = CWX | CWY | CWWidth | CWHeight | CWBorderWidth ; return ; } /**************************************************************** * Get a count of the managed kids of a parent, it is assumed that all * gadgets are always managed ****************/ int _XmGeoCount_kids( register CompositeWidget c ) { register int i, n = 0 ; /****************/ for( i = 0 ; i < c->composite.num_children ; i++ ) { if( c->composite.children[i]->core.managed ) { n++ ; } } return( n) ; } /**************************************************************** ARGSUSED * Assemble a kid box for each child widget and gadget, fill in data about * each widget and optionally set up uniform border widths. * Returns a list of records, last one has a 'kid' field of NULL. This memory * for this list should eventually be freed with a call to XtFree(). ****************/ /*ARGSUSED*/ XmKidGeometry _XmGetKidGeo( Widget wid, /* Widget w/ children. */ Widget instigator, /* May point to a child who */ XtWidgetGeometry *request, /* is asking to change. */ int uniform_border, /* T/F, enforce it. */ #if NeedWidePrototypes int border, #else Dimension border, /* Value to use if enforcing.*/ #endif /* NeedWidePrototypes */ int uniform_width_margins, /* unused. T/F, enforce it. */ int uniform_height_margins, /* unused. T/F, enforce it. */ Widget help, /* May point to a help kid. */ int geo_type ) /* Actual or preferred. */ { CompositeWidget c = (CompositeWidget) wid ; XmKidGeometry geo ; Widget kidWid ; int i ; int j = 0 ; Boolean helpFound = FALSE ; /****************/ geo = (XmKidGeometry) XtMalloc( (_XmGeoCount_kids (c) + 1) * sizeof (XmKidGeometryRec)) ; /* load all managed kids */ for( i = 0 ; i < c->composite.num_children ; i++ ) { kidWid = c->composite.children[i] ; if( XtIsManaged( kidWid) ) { if( kidWid == help ) { /* Save to put help widget at the end of the widget list.*/ helpFound = TRUE ; } else { geo[j].kid = kidWid ; _XmGeoLoadValues( kidWid, geo_type, instigator, request, &(geo[j].box)) ; if( uniform_border ) /* if asked override border */ { geo[j].box.border_width = border ; } j++ ; } } } if( helpFound ) /* put help guy into list */ { geo[j].kid = help ; _XmGeoLoadValues( help, geo_type, instigator, request, &(geo[j].box)) ; if( uniform_border ) /* if asked override border */ { geo[j].box.border_width = border ; } j++ ; } geo[j].kid = NULL ; /* signal end of list */ return( geo) ; } /****************************************************************/ void _XmGeoClearRectObjAreas( RectObj r, XWindowChanges *old ) { Widget parent = XtParent( r) ; int bw2 ; /****************/ bw2 = old->border_width << 1; XClearArea( XtDisplay( parent), XtWindow( parent), old->x, old->y, old->width + bw2, old->height + bw2, TRUE) ; bw2 = r->rectangle.border_width << 1; XClearArea( XtDisplay( parent), XtWindow( parent), (int) r->rectangle.x, (int) r->rectangle.y, (unsigned int) (r->rectangle.width + bw2), (unsigned int) (r->rectangle.height + bw2), TRUE) ; return ; } /**************************************************************** ARGSUSED * Take the kid geometry array and change each kid to match them. * remember not to do the resize of the instigator. * The kid geometry "kg" is assumed to be fully specified. ****************/ void _XmSetKidGeo( XmKidGeometry kg, Widget instigator ) { Widget w ; XtWidgetGeometry * b ; int i ; /****************/ for( i=0 ; kg[i].kid != NULL ; i++ ) { w = (Widget) kg[i].kid ; b = &(kg[i].box) ; if( w != instigator ) { XmeConfigureObject( w, b->x, b->y, b->width, b->height, b->border_width) ; } else { XtX( w) = b->x ; XtY( w) = b->y ; XtWidth( w) = b->width ; XtHeight( w) = b->height ; XtBorderWidth( w) = b->border_width ; } } return ; } /**************************************************************** * Returns TRUE if all specified geometries of geoA are equal to either the * specified geometries of geoB or to the geometry of the widget, and * vice versa. The XtCWQueryOnly bit is ignored. ****************/ Boolean _XmGeometryEqual( Widget wid, XtWidgetGeometry *geoA, XtWidgetGeometry *geoB ) { /****************/ if(!geoA){ /* For fixing OSF CR 5956 */ return(False); } if( IsWidth( geoA) || IsWidth( geoB) ) { if( IsWidth( geoA) && IsWidth( geoB) ) { if( geoA->width != geoB->width ) { return( FALSE) ; } } else { if( IsWidth( geoA) ) { if( geoA->width != XtWidth( wid) ) { return( FALSE) ; } } else { if( IsWidth( geoB) ) { if( geoB->width != XtWidth( wid) ) { return( FALSE) ; } } } } } if( IsHeight( geoA) || IsHeight( geoB) ) { if( IsHeight( geoA) && IsHeight( geoB) ) { if( geoA->height != geoB->height ) { return( FALSE) ; } } else { if( IsHeight( geoA) ) { if( geoA->height != XtHeight( wid) ) { return( FALSE) ; } } else { if( IsHeight( geoB) ) { if( geoB->height != XtHeight( wid) ) { return( FALSE) ; } } } } } if( IsBorder( geoA) || IsBorder( geoB) ) { if( IsBorder( geoA) && IsBorder( geoB) ) { if( geoA->border_width != geoB->border_width ) { return( FALSE) ; } } else { if( IsBorder( geoA) ) { if( geoA->border_width != XtBorderWidth( wid) ) { return( FALSE) ; } } else { if( IsBorder( geoB) ) { if( geoB->border_width != XtBorderWidth( wid) ) { return( FALSE) ; } } } } } if( IsX( geoA) || IsX( geoB) ) { if( IsX( geoA) && IsX( geoB) ) { if( geoA->x != geoB->x ) { return( FALSE) ; } } else { if( IsX( geoA) ) { if( geoA->x != XtX( wid) ) { return( FALSE) ; } } else { if( IsX( geoB) ) { if( geoB->x != XtX( wid) ) { return( FALSE) ; } } } } } if( IsY( geoA) || IsY( geoB) ) { if( IsY( geoA) && IsY( geoB) ) { if( geoA->y != geoB->y ) { return( FALSE) ; } } else { if( IsY( geoA) ) { if( geoA->y != XtY( wid) ) { return( FALSE) ; } } else { if( IsY( geoB) ) { if( geoB->y != XtY( wid) ) { return( FALSE) ; } } } } } return( TRUE) ; } /**************************************************************** * Returns TRUE if all specified geometries of "desired" correspond to * specified geometries of "response" and are equal to them. * The XtCWQueryOnly bit is ignored. ****************/ /*ARGSUSED*/ Boolean _XmGeoReplyYes( Widget wid, /* unused */ XtWidgetGeometry *desired, XtWidgetGeometry *response ) { /****************/ if(!response){ /* For fixing OSF CR 5956 */ return(False); } if( IsWidth( desired) ) { if( !IsWidth( response) || (desired->width != response->width) ) { return( FALSE) ; } } if( IsHeight( desired) ) { if( !IsHeight( response) || (desired->height != response->height) ) { return( FALSE) ; } } if( IsBorder( desired) ) { if( !IsBorder( response) || (desired->border_width != response->border_width) ) { return( FALSE) ; } } if( IsX( desired) ) { if( !IsX( response) || (desired->x != response->x) ) { return( FALSE) ; } } if( IsY( desired) ) { if( !IsY( response) || (desired->y != response->y) ) { return( FALSE) ; } } return( TRUE) ; } /**************************************************************** * This routine calls the geometry manager and accept the almost ****************/ XtGeometryResult _XmMakeGeometryRequest( Widget w, XtWidgetGeometry *geom ) { XtWidgetGeometry allowed ; XtGeometryResult answer ; /****************/ answer = XtMakeGeometryRequest( w, geom, &allowed) ; /* On an almost, accept the returned value and make * a second request to get an XtGeometryYes returned. */ if( answer == XtGeometryAlmost ) { /* The Intrinsics protocol guarantees a Yes response * to a request with identical geometry to that which * was returned by a previous request returning almost. */ *geom = allowed ; answer = XtMakeGeometryRequest( w, geom, &allowed) ; } return answer ; } /****************************************************************/ #ifdef DEBUG_GEOUTILS /****************************************************************/ void PrintBox( char * hdr, XmKidGeometry box) /**************** * ****************/ { /****************/ printf( "%sw: %X, m: 0x%X, x: %d, y: %d, w: %d, h: %d, b: %d\n", hdr, box->kid, box->box.request_mode, box->box.x, box->box.y, box->box.width, box->box.height, box->box.border_width) ; return ; } /****************************************************************/ void PrintList( char * hdr, XmKidGeometry listPtr) /**************** * ****************/ { int num ; char subhdr[256] ; /****************/ num = 0 ; while( listPtr->kid ) { sprintf( subhdr, "%si: %d ", hdr, num) ; PrintBox( subhdr, listPtr) ; ++num ; ++listPtr ; } return ; } /****************************************************************/ void PrintMatrix( char * hdr, XmGeoMatrix spec) /**************** * ****************/ { int row ; int col ; XmKidGeometry boxPtr ; XmGeoRowLayout layoutPtr ; char subhdr[256] ; /****************/ row = 1 ; boxPtr = spec->boxes ; layoutPtr = spec->layouts.row ; while( !(layoutPtr->end) ) { col = 1 ; while( boxPtr->kid ) { sprintf( subhdr, "%srow: %d, col: %d, ", hdr, row, col) ; PrintBox( subhdr, boxPtr) ; ++col ; ++boxPtr ; } ++row ; ++boxPtr ; ++layoutPtr ; } return ; } /****************************************************************/ #endif /* DEBUG_GEOUTILS */ /****************************************************************/