home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / src / ColumnWidget.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-10  |  9.7 KB  |  326 lines

  1. /* ColumnWidget -- a simple Composite widget that manages its children in
  2.  * a column.
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <X11/StringDefs.h>
  7. #include <X11/IntrinsicP.h>
  8. #include <X11/cursorfont.h>
  9. #include "ColumnWidgetP.h"
  10.  
  11. #define MAX(a,b) ((a)>(b)?(a):(b))
  12. #define MIN(a,b) ((a)<(b)?(a):(b))
  13.  
  14. static void Initialize();
  15. static void Resize();
  16. static void ChangeManaged();
  17. static XtGeometryResult GeometryManager();
  18. static XtGeometryResult PreferredSize();
  19. static XtGeometryResult try_layout();
  20.  
  21. ColumnClassRec columnClassRec = {
  22.     { /*
  23.        *    core_class fields
  24.        */
  25.     /* superclass        */    (WidgetClass)&compositeClassRec,
  26.     /* class_name        */    "Column",
  27.     /* widget_size        */    sizeof(ColumnRec),
  28.     /* class_initialize        */    NULL,
  29.     /* class_part_initialize    */    NULL,
  30.     /* class_inited        */    FALSE,
  31.     /* initialize        */    Initialize,
  32.     /* initialize_hook        */    NULL,
  33.     /* realize            */    XtInheritRealize,
  34.     /* actions            */    NULL,
  35.     /* num_actions        */    0,
  36.     /* resources        */    NULL,
  37.     /* resource_count        */    0,
  38.     /* xrm_class        */    NULLQUARK,
  39.     /* compress_motion        */    TRUE,
  40.     /* compress_exposure    */    TRUE,
  41.     /* compress_enterleave    */    TRUE,
  42.     /* visible_interest        */    FALSE,
  43.     /* destroy            */    NULL,
  44.     /* resize            */    Resize,
  45.     /* expose            */    NULL,
  46.     /* set_values        */    NULL,
  47.     /* set_values_hook        */    NULL,
  48.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  49.     /* get_values_hook        */    NULL,
  50.     /* accept_focus        */    NULL,
  51.     /* version            */    XtVersion,
  52.     /* callback_private        */    NULL,
  53.     /* tm_table            */    NULL,
  54.     /* query_geometry        */    PreferredSize,
  55.     /* display_accelerator    */    NULL,
  56.     /* extension        */    NULL
  57.     },
  58.     { /*
  59.        *    composite_class fields
  60.        */
  61.     /* geometry_manager        */    GeometryManager,
  62.     /* change_managed        */    ChangeManaged,
  63.     /* insert_child        */    XtInheritInsertChild,
  64.     /* delete_child        */    XtInheritDeleteChild,
  65.     /* extension        */    NULL
  66.     }
  67. };
  68.  
  69. WidgetClass columnWidgetClass = (WidgetClass) &columnClassRec;
  70.  
  71. static void Initialize (request, new)
  72.      ColumnWidget request, new;
  73. {
  74.     if (request->core.width  <= 0) new->core.width  = 5;
  75.     if (request->core.height <= 0) new->core.height = 5;
  76. }
  77.  
  78. static void do_layout (ColumnWidget);
  79.  
  80. static void Resize (w)
  81.      ColumnWidget w;
  82. {
  83.     printf("Resize\n");fflush(stdout);
  84.     do_layout (w);
  85. }
  86.  
  87. static void
  88. do_layout (parent)
  89.      ColumnWidget parent;
  90. {
  91.     Widget child;
  92.     int i;
  93.     Dimension childheight = 0;
  94.     Position ypos = 0;
  95.     Dimension pad = 0;
  96.     int n_managed_children = 0;
  97.     
  98.     /* compute total and height of all managed children
  99.      */
  100.     for (i=0; i < parent->composite.num_children; i++) {
  101.        child = parent->composite.children[i];
  102.        if (child->core.managed) {
  103.       n_managed_children++;
  104.       childheight += child->core.height + (child->core.border_width * 2);
  105.        }
  106.     }
  107.  
  108.     printf("kids=%d, total-h=%d\n", n_managed_children, childheight);
  109.     fflush(stdout);
  110.  
  111.     /* divide remaining space by number of children
  112.      */
  113.     if ((n_managed_children > 1) && (parent->core.height > childheight))
  114.       pad = (parent->core.height - childheight) / (n_managed_children - 1);
  115.  
  116.     printf("pad = %d\n", pad);
  117.  
  118.     /* move things around
  119.      */
  120.     for (i = 0; i < parent->composite.num_children; i++) {
  121.        child = parent->composite.children[i];
  122.        if (child->core.managed) {
  123.       printf("moving kid %d to 0, %d + %d\n", i, ypos, child->core.height);
  124.       fflush(stdout);
  125.       XtMoveWidget (child, 0, ypos);
  126.       ypos += pad + child->core.height + (child->core.border_width * 2);
  127.       }
  128.    }
  129. }
  130.  
  131. static XtGeometryResult PreferredSize (w, request, preferred)
  132.      ColumnWidget w;
  133.      XtWidgetGeometry *request, *preferred;
  134. {
  135.     Widget child;
  136.     int i;
  137.     
  138.     printf("PreferredSize\n");fflush(stdout);
  139.  
  140.     /* if no changes to w or h, just agree */
  141.     if (! (request->request_mode & CWWidth) &&
  142.     ! (request->request_mode & CWHeight))
  143.       return XtGeometryYes;
  144.  
  145.     /* calculate min size */
  146.     preferred->width = 0;
  147.     preferred->height = 0;
  148.     for (i=0; i<w->composite.num_children; i++) {
  149.        if (child->core.managed) {
  150.       preferred->width += child->core.width + 2*child->core.border_width;
  151.       preferred->height += child->core.height + 2*child->core.border_width;
  152.        }
  153.     }
  154.     preferred->request_mode = CWWidth|CWHeight;
  155.  
  156.     /* if both w and h are requested... */
  157.     if ((request->request_mode & CWWidth) &&
  158.     (request->request_mode & CWHeight)) {
  159.        /* if we are to be the same or bigger, say ok */
  160.        if ((preferred->width >= request->width) &&
  161.        (preferred->height >= request->height)) {
  162.       preferred->width = request->width;
  163.       preferred->height = request->height;
  164.       return XtGeometryYes;
  165.        }
  166.        /* if both dimensions unacceptable, say no */
  167.        else
  168.          if ((preferred->width < request->width) &&
  169.          (preferred->height < request->height))
  170.        return XtGeometryNo;
  171.          /* otherwise, one must be right, so say almost */
  172.          else
  173.        return XtGeometryAlmost;
  174.     }
  175.     /* if only the width is requested, either it's ok or it isn't */
  176.     else
  177.       if (request->request_mode & CWWidth) {
  178.      if (preferred->width >= request->width) {
  179.         preferred->width = request->width;
  180.         return XtGeometryYes;
  181.      }
  182.      else
  183.         return XtGeometryNo;
  184.       }
  185.     /* if only height is requested... */
  186.     else
  187.       if (request->request_mode & CWHeight) {
  188.      if (preferred->height >= request->height) {
  189.         preferred->height = request->height;
  190.         return XtGeometryYes;
  191.      }
  192.      else
  193.         return XtGeometryNo;
  194.       }
  195.     return XtGeometryYes;
  196. }
  197.  
  198. static XtGeometryResult GeometryManager (w, request, reply)
  199.      Widget w;
  200.      XtWidgetGeometry *request, *reply;
  201. {
  202.     ColumnWidget cw = (ColumnWidget) w->core.parent;
  203.     Mask mask;
  204.     XtGeometryResult result;
  205.     Dimension wdelta, hdelta;
  206.  
  207.     /* child-widgets aren't allowed to change their position
  208.      */
  209.     if (((request->request_mode & CWX) && request->x != w->core.x) ||
  210.     ((request->request_mode & CWY) && request->y != w->core.y))
  211.       return XtGeometryNo;
  212.  
  213.     if (request->request_mode & (CWWidth|CWHeight|CWBorderWidth)) {
  214.        /* save orig size, set corresponding widget fields to requested sizes */
  215.        Dimension savewidth = w->core.width;
  216.        Dimension saveheight = w->core.height;
  217.        Dimension saveborderwidth = w->core.border_width;
  218.        if (request->request_mode & CWWidth) w->core.width = request->width;
  219.        if (request->request_mode & CWHeight) w->core.height = request->height;
  220.        if (request->request_mode & CWBorderWidth)
  221.           w->core.border_width = request->border_width;
  222.        
  223.        /* see if we can still handle all the children if the req is granted */
  224.        result = try_layout(cw, &mask, &wdelta, &hdelta);
  225.  
  226.        /* if the children won't fit, restore widget to orig size, say no */
  227.        if (result == XtGeometryNo) {
  228.       w->core.width = savewidth;
  229.       w->core.height = saveheight;
  230.       w->core.border_width = saveborderwidth;
  231.       return XtGeometryNo;
  232.        }
  233.        /* if only one dim. doesn't fit, restore that one, and say almost */
  234.        if (result == XtGeometryAlmost)
  235.       if (! (mask & CWWidth)) {
  236.          reply->width = w->core.width = savewidth;
  237.       if (! (mask & CWHeight)) {
  238.          reply->height = w->core.height = saveheight;
  239.          reply->border_width = saveborderwidth;
  240.          w->core.border_width = saveborderwidth;
  241.       }
  242.       return XtGeometryAlmost;
  243.        }
  244.        /* else everything fits... */
  245.        do_layout (cw);
  246.        return XtGeometryYes;
  247.     }
  248.     return XtGeometryYes;
  249. }
  250.  
  251. static XtGeometryResult try_layout (parent, mask, w_delta, h_delta)
  252.      ColumnWidget parent;
  253.      Mask *mask;
  254.      Dimension *w_delta, *h_delta;
  255. {
  256.     int i;
  257.     Dimension max_width = 0, total_height = 0;
  258.     
  259.     /* get bbox of all children */
  260.     for (i=0; i<parent->composite.num_children; i++) {
  261.        Widget child;
  262.        Dimension width, height;
  263.        child = parent->composite.children[i];
  264.        if (child->core.managed) {
  265.       width  = child->core.width  + 2*child->core.border_width;
  266.       height = child->core.height + 2*child->core.border_width;
  267.       total_height += height;
  268.       max_width = MAX(max_width, width);
  269.        }
  270.     }
  271.     /* if everyone doesn't fit, ask if we can grow.  Return result, after
  272.        setting the mask to indicate which (if any) dimension is ok */
  273.     if (total_height > parent->core.height ||
  274.     max_width > parent->core.width) {
  275.        XtGeometryResult result;
  276.        Dimension replyWidth, replyHeight;
  277.        Dimension width  = MAX(max_width, parent->core.width);
  278.        Dimension height = MAX(total_height, parent->core.height);
  279.  
  280.        result = XtMakeResizeRequest((Widget) parent, width, height,
  281.                     &replyWidth, &replyHeight);
  282.        *mask = 0;
  283.        if (max_width == replyWidth) *mask = CWWidth;
  284.        if (total_height == replyHeight) *mask |= CWHeight;
  285.        if (result == XtGeometryAlmost)
  286.           XtMakeResizeRequest ((Widget) parent, replyWidth, replyHeight,
  287.                    NULL, NULL);
  288.        *w_delta = max_width - parent->core.width;
  289.        *h_delta = total_height - parent->core.height;
  290.        return result;
  291.     }
  292.     /* if everybody fits, just say yes */
  293.     *mask = CWWidth|CWHeight;
  294.     return XtGeometryYes;
  295. }
  296.  
  297.  
  298. static void ChangeManaged (w)
  299.      ColumnWidget w;
  300. {
  301.     XtGeometryResult result;
  302.     Dimension width, height, delta, i;
  303.     Mask mask;
  304.     Widget child;
  305.     
  306.     /* see if everyone fits */
  307.     result = try_layout (w, &mask, &width, &height);
  308.  
  309.     /* if no, shrink the kids */
  310.     if (result != XtGeometryYes) {
  311.        if (w->composite.num_children > 0) {
  312.       delta = width / w->composite.num_children;
  313.       for (i=0; i < w->composite.num_children; i++) {
  314.          child = w->composite.children[i];
  315.          height = MIN((int)child->core.height,
  316.               (int)w->core.height - (int)child->core.border_width);
  317.          if (child->core.managed)
  318.             XtResizeWidget (child, child->core.width - delta, height,
  319.                 child->core.border_width);
  320.       }
  321.        }
  322.     }
  323.     /* move 'em out */
  324.     do_layout(w);
  325. }
  326.