home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / vroom / Row.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  13.8 KB  |  532 lines

  1. /*******************************************************************************
  2.  * Row.c: Methods for the Row widget
  3.  *         From:
  4.  *                   The X Window System, 
  5.  *            Programming and Applications with Xt
  6.  *                   OSF/Motif Edition
  7.  *         by
  8.  *                Douglas Young
  9.  *              Prentice Hall, 1990
  10.  *
  11.  *                 Example described on pages: 375-390
  12.  *
  13.  * Modified slightly by Chris Fouts, Silicon Graphics, Inc. 1994
  14.  *
  15.  *  Copyright 1989 by Prentice Hall
  16.  *  All Rights Reserved
  17.  *
  18.  * This code is based on the OSF/Motif widget set and the X Window System
  19.  *
  20.  * Permission to use, copy, modify, and distribute this software for 
  21.  * any purpose and without fee is hereby granted, provided that the above
  22.  * copyright notice appear in all copies and that both the copyright notice
  23.  * and this permission notice appear in supporting documentation.
  24.  *
  25.  * Prentice Hall and the author disclaim all warranties with regard to 
  26.  * this software, including all implied warranties of merchantability and
  27.  * fitness.  In no event shall Prentice Hall or the author be liable for any
  28.  * special, indirect or cosequential damages or any damages whatsoever
  29.  * resulting from  loss of use, data or profits, whether in an action of
  30.  * contract, negligence  or other tortious action, arising out of or in
  31.  * connection with the use  or performance of this software.
  32.  *
  33.  * Open Software Foundation is a trademark of The Open Software Foundation, Inc.
  34.  * OSF is a trademark of Open Software Foundation, Inc.
  35.  * OSF/Motif is a trademark of Open Software Foundation, Inc.
  36.  * Motif is a trademark of Open Software Foundation, Inc.
  37.  * DEC is a registered trademark of Digital Equipment Corporation
  38.  * HP is a registered trademark of the Hewlett Packard Company
  39.  * DIGITAL is a registered trademark of Digital Equipment Corporation
  40.  * X Window System is a trademark of the Massachusetts Institute of Technology
  41.  ******************************************************************************/
  42.  
  43.  
  44. #include    <stdio.h>
  45. #include    <X11/IntrinsicP.h>
  46. #include    <X11/Intrinsic.h>
  47. #include    <X11/Composite.h>
  48. #include    <X11/CompositeP.h>
  49. #include    <X11/Xm/XmStrDefs.h>
  50. #include    "RowP.h"
  51. #include    "Row.h"
  52. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  53. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  54.  
  55. /* BEGIN PROTOTYPES -S Row.c */
  56. static void                 ChangeManaged( Widget w ) ;
  57. static void                 do_layout( XsRowWidget parent ) ;
  58. static XtGeometryResult     GeometryManager( Widget w,
  59.                                 XtWidgetGeometry *request,
  60.                                 XtWidgetGeometry *reply ) ;
  61. static void                 Initialize( Widget request, Widget new,
  62.                                 ArgList args, Cardinal *numArgs ) ;
  63. static XtGeometryResult     PreferredSize( Widget w,
  64.                                 XtWidgetGeometry *request,
  65.                                 XtWidgetGeometry *preferred ) ;
  66. static void                 Resize( Widget w ) ;
  67. static XtGeometryResult     try_layout( XsRowWidget parent, Mask *mask,
  68.                                 Dimension *w_delta, Dimension *h_delta ) ;
  69. /* END PROTOTYPES -S Row.c */
  70.  
  71. static XtResource    resources[] =
  72.         {
  73.         {    XmNspacing, XmCSpacing, XtRInt, sizeof( int ),
  74.             XtOffset( XsRowWidget, row.spacing ), XtRString, "5" },
  75.         } ;
  76.  
  77.  
  78. XsRowClassRec XsrowClassRec = {
  79.     {
  80.     /* core_class members      */
  81.     (WidgetClass) &compositeClassRec, /* superclass         */
  82.     "Row",                            /* class_name         */
  83.     sizeof(XsRowRec),                 /* widget_size        */
  84.     NULL,                             /* class_initialize   */
  85.     NULL,                             /* class_part_init    */    
  86.     FALSE,                            /* class_inited       */    
  87.     Initialize,                       /* initialize         */
  88.     NULL,                             /* initialize_hook    */    
  89.     XtInheritRealize,                 /* realize            */
  90.     NULL,                             /* actions            */
  91.     0,                                /* num_actions        */    
  92.     resources,                        /* resources          */
  93.     XtNumber( resources ),            /* num_resources      */
  94.     NULLQUARK,                        /* xrm_class          */
  95.     TRUE,                             /* compress_motion    */    
  96.     TRUE,                             /* compress_exposure  */    
  97.     TRUE,                             /* compress_enterleave*/    
  98.     FALSE,                            /* visible_interest   */
  99.     NULL,                             /* destroy            */
  100.     Resize,                           /* resize             */
  101.     NULL,                             /* expose             */
  102.     NULL,                             /* set_values         */
  103.     NULL,                             /* set_values_hook    */
  104.     XtInheritSetValuesAlmost,         /* set_values_almost  */
  105.     NULL,                             /* get_values_hook    */    
  106.     NULL,                             /* accept_focus       */
  107.     XtVersion,                        /* version            */    
  108.     NULL,                             /* callback_private   */
  109.     NULL,                             /* tm_table           */
  110.     PreferredSize,                    /* query_geometry     */    
  111.     NULL,                             /* display_accelerator*/
  112.     NULL,                             /* extension          */
  113.     },
  114.     {
  115.     /* composite_class members */
  116.     GeometryManager,                  /* geometry_manager   */
  117.     ChangeManaged,                    /* change_managed     */
  118.     XtInheritInsertChild,             /* insert_child       */    
  119.     XtInheritDeleteChild,             /* delete_child       */    
  120.     NULL,                             /* extension          */
  121.     },
  122.     {
  123.     /* Row class members */
  124.     0,                                /* empty              */    
  125.     }
  126. };
  127.  
  128.  
  129. WidgetClass xsRowWidgetClass = (WidgetClass) &XsrowClassRec;
  130.  
  131.  
  132. static void
  133. Initialize(
  134.     Widget        request,
  135.     Widget        new,
  136.     ArgList        args,
  137.     Cardinal    *numArgs
  138.     )
  139. {
  140.     XsRowWidget    reqRow = (XsRowWidget)request ;
  141.     XsRowWidget    newRow = (XsRowWidget)new ;
  142.  
  143.     if( reqRow->core.width <= 0 )
  144.     {
  145.         newRow->core.width = 5 ;
  146.     }
  147.     if( reqRow->core.height <= 0 )
  148.     {
  149.         newRow->core.height = 5 ;
  150.     }
  151.     if( reqRow->row.spacing < 0 )
  152.     {
  153.         newRow->row.spacing = 5 ;
  154.     }
  155.  
  156.  
  157.  
  158. static void
  159. Resize(
  160.     Widget    w
  161.     )
  162. {
  163.     do_layout( (XsRowWidget)w ) ;
  164.  
  165.  
  166.  
  167. static void
  168. do_layout(
  169.     XsRowWidget    parent
  170.     )
  171. {
  172.     Widget        child ;
  173.     int        i ;
  174.     Dimension    childwidth = 2 * parent->row.spacing ;
  175.     Position    xpos = parent->row.spacing ;
  176.     Dimension    pad = 0 ;
  177.     int        n_managed_children = 0 ;
  178.  
  179.     /*
  180.      * Compute the total width of all managed children and
  181.      * determine how many children are managed.
  182.      */
  183.     for( i = 0 ; i < parent->composite.num_children ; i++ )
  184.     {
  185.         child = parent->composite.children[i] ;
  186.         if( child->core.managed )
  187.         {
  188.             n_managed_children++;
  189.             childwidth += child->core.width + 
  190.                     child->core.border_width * 2 ;
  191.         }
  192.     }
  193.     /*
  194.      *  Divide any remaining space by the number 
  195.      *  of children.
  196.      */
  197.     if( ( n_managed_children > 1 ) && ( parent->core.width > childwidth ) )
  198.     {
  199.         pad = ( parent->core.width - childwidth ) /
  200.             ( n_managed_children - 1 ) ;
  201.     }
  202.     /*
  203.      * Position all children.
  204.      */
  205.     for( i = 0 ; i < parent->composite.num_children ; i++ )
  206.     {
  207.         child = parent->composite.children[i] ;
  208.         if( child->core.managed )
  209.         {
  210.             XtMoveWidget( child, xpos, parent->row.spacing ) ;
  211.             xpos += pad + child->core.width + 
  212.                      child->core.border_width * 2 ;
  213.         }
  214.     }
  215. }
  216.  
  217.  
  218.  
  219. static XtGeometryResult
  220. PreferredSize(
  221.     Widget            w,
  222.     XtWidgetGeometry    *request,
  223.     XtWidgetGeometry    *preferred
  224.     )
  225. {
  226.     XsRowWidget    row = (XsRowWidget)w ;
  227.     Widget        child ;
  228.     int        i ;
  229.  
  230.     /*
  231.      * If no changes are being made to width or 
  232.      * height, just agree. 
  233.      */
  234.     if( !( request->request_mode & CWWidth ) &&
  235.         !( request->request_mode & CWHeight ) )
  236.     {
  237.         return( XtGeometryYes ) ;
  238.     }
  239.  
  240.     /*
  241.      * Calculate our minimum size.
  242.      */
  243.     preferred->width = row->row.spacing ;
  244.     preferred->height = 0 ;       
  245.     for( i = 0 ; i < row->composite.num_children; i++ )
  246.     {
  247.         child = row->composite.children[i] ;
  248.         if( child->core.managed )
  249.         {
  250.             Dimension    h ;
  251.  
  252.             preferred->width += child->core.width + 
  253.                     child->core.border_width * 2 +
  254.                     row->row.spacing ;
  255.             h = child->core.height + child->core.border_width * 2 +
  256.                 row->row.spacing * 2 ;
  257.             if( preferred->height < h )
  258.             {
  259.                 preferred->height = h ;
  260.             }
  261.         }
  262.     }
  263.     preferred->request_mode = CWWidth | CWHeight;
  264.  
  265.     /* 
  266.      * If both width and height are requested.
  267.      */
  268.     if( ( request->request_mode & CWWidth ) && 
  269.         ( request->request_mode & CWHeight ) )
  270.     {
  271.         /* 
  272.          * If we are to be the same or bigger, say ok.
  273.          */
  274.         if( preferred->width <= request->width &&
  275.             preferred->height <= request->height )
  276.         {
  277.             preferred->width  = request->width;
  278.             preferred->height = request->height;
  279.             return( XtGeometryYes ) ;
  280.         }
  281.         /*
  282.          * If both dimensions are unacceptable, say no.
  283.          */
  284.         else if( preferred->width < request->width && 
  285.             preferred->height < request->height )
  286.         {
  287.             return( XtGeometryNo ) ;
  288.         }
  289.         /*
  290.          * Otherwise one must be right, so say almost.
  291.          */
  292.         else
  293.         {
  294.             return( XtGeometryAlmost ) ;
  295.         }
  296.     }
  297.     /*
  298.      * If only the width is requested, either it's 
  299.      * OK or it isn't. Same for height.
  300.      */
  301.     else if( request->request_mode & CWWidth )
  302.     {
  303.         if( preferred->width <= request->width )
  304.         {
  305.             preferred->width = request->width ;
  306.             return( XtGeometryYes ) ;
  307.         } 
  308.         else
  309.         {
  310.             return( XtGeometryNo ) ;
  311.         }
  312.     }
  313.     else if(request->request_mode & CWHeight)
  314.     {
  315.         if( preferred->height <= request->height )
  316.         {
  317.             preferred->height = request->height ;
  318.             return( XtGeometryYes ) ;
  319.         }
  320.         else
  321.         {
  322.             return( XtGeometryNo ) ;
  323.         }
  324.     }
  325.     return( XtGeometryYes ) ;
  326. }
  327.  
  328.  
  329.  
  330. static XtGeometryResult
  331. GeometryManager(
  332.     Widget            w,
  333.     XtWidgetGeometry    *request,
  334.     XtWidgetGeometry    *reply
  335.     )
  336. {
  337.     XsRowWidget        rw = (XsRowWidget)( w->core.parent ) ;
  338.     Mask            mask ;
  339.     XtGeometryResult    result ;
  340.     Dimension        wdelta ;
  341.     Dimension        hdelta ;
  342.  
  343.     /*
  344.      * Say no.  We control the vertical....
  345.      */
  346.     if( ( request->request_mode & CWX && request->x != w->core.x ) ||
  347.         ( request->request_mode & CWY && request->y != w->core.y ) )
  348.     {
  349.         return( XtGeometryNo ) ;
  350.     }
  351.     /*
  352.      *  Otherwise, grant all requests if they fit.
  353.      */
  354.     if( request->request_mode & ( CWWidth | CWHeight | CWBorderWidth ) )
  355.     {
  356.         /*
  357.          * Save the original widget size, and set the 
  358.          * corresponding widget fields to the requested sizes.
  359.          */
  360.         Dimension savewidth       = w->core.width;
  361.         Dimension saveheight      = w->core.height;
  362.         Dimension saveborderwidth = w->core.border_width;
  363.  
  364.         if( request->request_mode & CWWidth )
  365.         {
  366.             w->core.width = request->width ;
  367.         }
  368.         if( request->request_mode & CWHeight )
  369.         {
  370.             w->core.height = request->height ;
  371.         }
  372.         if( request->request_mode & CWBorderWidth )
  373.         {
  374.             w->core.border_width = request->border_width ;
  375.         }
  376.         /*
  377.          * See if we can still handle all the children 
  378.          * if the request is granted.
  379.          */
  380.         result = try_layout( rw, &mask, &wdelta, &hdelta ) ;
  381.         /*
  382.          * If the children won't fit, restore the widget to its
  383.          * original size, and return no.
  384.          */
  385.         if( result == XtGeometryNo )
  386.         {
  387.             w->core.width  = savewidth ;
  388.             w->core.height = saveheight ;
  389.             w->core.border_width = saveborderwidth ;
  390.             return( XtGeometryNo ) ;
  391.         }
  392.         /*
  393.          * If only one dimension fits, restore the one that
  394.          * doesn't fit and return "almost".
  395.          */
  396.         if( result == XtGeometryAlmost )
  397.         {
  398.             reply->request_mode = request->request_mode ;
  399.             if( !( mask & CWWidth ) )
  400.             {
  401.                 reply->width = w->core.width = savewidth ;
  402.                 reply->border_width  = saveborderwidth ;
  403.                 w->core.border_width = saveborderwidth ;
  404.             }
  405.             if( !( mask & CWHeight ) )
  406.             {
  407.                 reply->height = w->core.height = saveheight ;
  408.             }
  409.  
  410.             return( XtGeometryAlmost ) ;
  411.         }
  412.         /*
  413.          * If we got here, everything must fit, so reposition
  414.          * all children based on the new size, and return "yes".
  415.          */
  416.         do_layout( rw ) ;
  417.         return( XtGeometryYes ) ;
  418.     }
  419.     return( XtGeometryYes ) ;
  420. }
  421.  
  422.  
  423.  
  424. static XtGeometryResult 
  425. try_layout(
  426.     XsRowWidget    parent,
  427.     Mask        *mask,
  428.     Dimension    *w_delta,
  429.     Dimension    *h_delta
  430.     )
  431. {
  432.     int        i ;
  433.     Dimension    total_width = 2 * parent->row.spacing ;
  434.     Dimension    max_height = 2 * parent->row.spacing ;
  435.  
  436.     /*
  437.      * Get the bounding width and height of all children.
  438.      */
  439.     for( i = 0 ; i < parent->composite.num_children ; i++ )
  440.     {
  441.         Widget        child ;
  442.         Dimension    width ;
  443.         Dimension    height ;
  444.  
  445.         child = parent->composite.children[i] ;
  446.         if( child->core.managed )
  447.         {
  448.             height = child->core.height +
  449.                     child->core.border_width * 2 +
  450.                     parent->row.spacing * 2 ;
  451.             width  = child->core.width +
  452.                     child->core.border_width * 2 ;
  453.             total_width += width ;
  454.             max_height = MAX( max_height, height ) ;
  455.         }
  456.     }
  457.     if( parent->composite.num_children > 1 )
  458.     {
  459.         total_width += ( parent->composite.num_children - 1 ) *
  460.             parent->row.spacing ;
  461.     }
  462.  
  463.     /*
  464.      *  If everyone doesn't fit, ask if we can grow. Return the 
  465.      *  result, after setting the mask to indicate which (if 
  466.      *  any) dimension is ok.
  467.      */
  468.     if( total_width > parent->core.width || 
  469.         max_height > parent->core.height )
  470.     {
  471.         XtGeometryResult    result ;
  472.         Dimension        replyWidth ;
  473.         Dimension        replyHeight ;
  474.         Dimension    width  = MAX(total_width, parent->core.width);
  475.         Dimension    height = MAX(max_height, parent->core.height);
  476.  
  477.         result = XtMakeResizeRequest( (Widget)parent, width, height,
  478.                         &replyWidth, &replyHeight ) ;
  479.         *mask = NULL ;
  480.         if( total_width == replyWidth )
  481.         {
  482.             *mask  = CWWidth ;
  483.         }
  484.         if( max_height == replyHeight )
  485.         {
  486.             *mask |= CWHeight ;
  487.         }
  488.  
  489.         if( result == XtGeometryAlmost )
  490.         {
  491.             XtMakeResizeRequest( (Widget)parent, replyWidth,
  492.                         replyHeight, NULL, NULL) ;
  493.         }
  494.         *w_delta = total_width - parent->core.width;
  495.         *h_delta = max_height - parent->core.height;
  496.         return( result ) ;
  497.     }
  498.     /*
  499.      * If everybody fits, just return yes.
  500.      */
  501.     *mask = CWWidth | CWHeight ;
  502.     return( XtGeometryYes ) ;
  503. }
  504.  
  505.  
  506.  
  507. static void
  508. ChangeManaged(
  509.     Widget    w
  510.     )
  511. {
  512.     XsRowWidget        row = (XsRowWidget)w ;
  513.     XtGeometryResult    result;
  514.     Dimension           width, height, delta;
  515.     int                 i;
  516.     Mask                mask;
  517.     Widget              child;
  518.  
  519.     /*
  520.      * See if all children fit.
  521.      */
  522.     result = try_layout( row, &mask, &width, &height ) ;
  523.  
  524.     /*
  525.      * Move all children to their new positions.
  526.      */
  527.     do_layout( row ) ;
  528. }
  529.  
  530.