home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / x / volume10 / xt-examples / part05 / MinMax.c < prev    next >
C/C++ Source or Header  |  1990-11-04  |  16KB  |  513 lines

  1. /***********************************************************
  2. Copyright 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
  3.  
  4.                         All Rights Reserved
  5.  
  6. Permission to use, copy, modify, and distribute these examples for any
  7. purpose and without fee is hereby granted, provided that the above
  8. copyright notice appear in all copies and that both that copyright
  9. notice and this permission notice appear in supporting documentation,
  10. and that the name of Digital not be used in advertising or publicity
  11. pertaining to distribution of the software without specific, written
  12. prior permission.
  13.  
  14. DIGITAL AND THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  15. SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  16. FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
  17. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  18. OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  19. OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  20. OR PERFORMANCE OF THIS SOFTWARE.
  21.  
  22. ******************************************************************/
  23.  
  24. #include <X11/IntrinsicP.h>    /* Intrinsics header file */
  25. #include <X11/StringDefs.h>    /* Resource string definitions */
  26. #include "MinMaxP.h"        /* MinMax private header file */
  27. #include "LabelGadge.h"        /* To check LabelGadgets */
  28.  
  29. #define Offset(field) XtOffsetOf(MinMaxRec, minMax.field)
  30.  
  31. static XtResource resources[] = {
  32.     {XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
  33.     Offset(margin), XtRImmediate, (XtPointer) 10},
  34. };
  35.  
  36. #undef Offset
  37.  
  38. #define Offset(field) XtOffsetOf(MinMaxConstraintRec, field)
  39.  
  40. static XtResource constraintResources[] = {
  41.     {XtNminWidth, XtCMinWidth, XtRShort, sizeof(short),
  42.         Offset(minMax.min_width), XtRImmediate, (XtPointer) -1},
  43.     {XtNmaxWidth, XtCMaxWidth, XtRShort, sizeof(short),
  44.         Offset(minMax.max_width), XtRImmediate, (XtPointer) -1},
  45.     {XtNminHeight, XtCMinHeight, XtRShort, sizeof(short),
  46.         Offset(minMax.min_height), XtRImmediate, (XtPointer) -1},
  47.     {XtNmaxHeight, XtCMaxHeight, XtRShort, sizeof(short),
  48.         Offset(minMax.max_height), XtRImmediate, (XtPointer) -1},
  49. };
  50. #undef Offset
  51.  
  52. /* Forward declarations */
  53.  
  54. static void ChangeManaged(), Initialize(), ConstraintInitialize(),
  55.     Resize(), InsertChild(), DeleteChild(), Redisplay();
  56. static XtGeometryResult GeometryManager();
  57. static Boolean SetValues(), AcceptFocus(), ConstraintSetValues();
  58.  
  59. static CompositeClassExtensionRec compositeExtension = {
  60.     /* next_extension        */ NULL,
  61.     /* record_type        */ NULLQUARK,
  62.     /* version            */ XtCompositeExtensionVersion,
  63.     /* record_size        */ sizeof(CompositeClassExtensionRec),
  64.     /* accepts_objects        */ TRUE
  65. };
  66.  
  67. MinMaxClassRec minMaxClassRec = {
  68.     /* Core class part */
  69.   {
  70.     /* superclass         */    (WidgetClass) &constraintClassRec,
  71.     /* class_name         */ "MinMax",
  72.     /* widget_size         */ sizeof(MinMaxRec),
  73.     /* class_initialize      */ NULL,
  74.     /* class_part_initialize */ NULL,
  75.     /* class_inited          */    FALSE,
  76.     /* initialize         */    Initialize,
  77.     /* initialize_hook       */    NULL,
  78.     /* realize             */    XtInheritRealize,
  79.     /* actions             */    NULL,
  80.     /* num_actions         */    0,
  81.     /* resources         */    resources,
  82.     /* num_resources         */    XtNumber(resources),
  83.     /* xrm_class         */    NULLQUARK,
  84.     /* compress_motion         */    TRUE,
  85.     /* compress_exposure     */    XtExposeCompressMultiple,
  86.     /* compress_enterleave   */    TRUE,
  87.     /* visible_interest         */    FALSE,
  88.     /* destroy             */    NULL,
  89.     /* resize             */    Resize,
  90.     /* expose             */    Redisplay,
  91.     /* set_values         */    SetValues,
  92.     /* set_values_hook       */    NULL,            
  93.     /* set_values_almost     */    XtInheritSetValuesAlmost,  
  94.     /* get_values_hook       */    NULL,            
  95.     /* accept_focus         */    AcceptFocus,
  96.     /* version             */    XtVersion,
  97.     /* callback offsets      */    NULL,
  98.     /* tm_table              */    NULL,
  99.     /* query_geometry         */    XtInheritQueryGeometry,
  100.     /* display_accelerator   */    NULL,
  101.     /* extension         */    NULL,
  102.   },
  103.    /* Composite class part */
  104.   {
  105.     /* geometry_manager         */    GeometryManager,
  106.     /* change_managed         */    ChangeManaged,
  107.     /* insert_child         */    InsertChild,
  108.     /* delete_child         */    DeleteChild,
  109.     /* extension         */    (XtPointer) &compositeExtension,
  110.   },
  111.    /* Constraint class part */
  112.   {
  113.    /* resources             */ constraintResources,
  114.    /* num_resources         */ XtNumber(constraintResources),
  115.    /* constraint_size         */ sizeof(MinMaxConstraintRec),
  116.    /* initialize         */ ConstraintInitialize,
  117.    /* destroy             */ NULL,
  118.    /* set_values         */ ConstraintSetValues,
  119.    /* extension             */ NULL
  120.   },
  121.    /* MinMax class part */
  122.   {
  123.     /* extension         */    NULL,
  124.   }
  125. };
  126.  
  127. WidgetClass minMaxWidgetClass = (WidgetClass) &minMaxClassRec;
  128.  
  129. static void InsertChild(w)
  130.     Widget w;
  131. {
  132.     String params[2];
  133.     Cardinal num_params;
  134.     Widget parent = XtParent(w);
  135.  
  136.     if (!XtIsWidget(w) && !XtIsSubclass(w, labelGadgetClass)) {
  137.     params[0] = XtClass(w)->core_class.class_name;
  138.     params[1] = XtClass(parent)->core_class.class_name;
  139.     num_params = 2;
  140.     XtAppErrorMsg(XtWidgetToApplicationContext(w),
  141.         "childError", "class", "WidgetError",
  142.         "Children of class %s cannot be added to %n widgets",
  143.         params, &num_params);
  144.     }
  145.  
  146.     (*((CompositeWidgetClass)(minMaxWidgetClass->
  147.         core_class.superclass))->composite_class.insert_child) (w);
  148. }
  149.  
  150. static void DeleteChild(w)
  151.     Widget w;
  152. {
  153.     MinMaxWidget minMax = (MinMaxWidget) XtParent(w);
  154.  
  155.     if (minMax->minMax.last_focus == w) {
  156.     minMax->minMax.last_focus = NULL;
  157.     }
  158.  
  159.     (*((CompositeWidgetClass)(minMaxWidgetClass->
  160.         core_class.superclass))->composite_class.delete_child) (w);
  161. }
  162.  
  163. static void Initialize(req, new, args, num_args)
  164.     Widget req, new;
  165.     ArgList args;
  166.     Cardinal *num_args;
  167. {
  168.     ((MinMaxWidget) new)->minMax.last_focus = NULL;
  169. }
  170.  
  171. static void CheckConstraint(w, smaller, larger, which)
  172.     Widget w;
  173.     short *smaller, *larger;
  174.     String which;
  175. {
  176.     String params[3];
  177.     Cardinal num_params;
  178.  
  179.     if (*smaller > *larger) {
  180.     params[0] = params[1] = which;
  181.     params[2] = XtName(w);
  182.     num_params = 3;
  183.     XtAppWarningMsg(XtWidgetToApplicationContext(w),
  184.         "constraintError",
  185.         "width", "WidgetError", 
  186.         "Min %s greater than max %s for widget %s",
  187.         params, &num_params);
  188.     *smaller = *larger;
  189.     }
  190. }
  191.  
  192. static void ResizeWithinConstraints(w, width, height)
  193.     Widget w;
  194.     Dimension *width, *height;
  195. {
  196.     register MinMaxConstraint mmc =
  197.         (MinMaxConstraint) w->core.constraints;
  198.  
  199.     if (*width < mmc->minMax.min_width) {
  200.     *width = mmc->minMax.min_width;
  201.     } else if (*width > mmc->minMax.max_width) {
  202.     *width = mmc->minMax.max_width;
  203.     }
  204.  
  205.     if (*height < mmc->minMax.min_height) {
  206.     *height = mmc->minMax.min_height;
  207.     } else if (*height > mmc->minMax.max_height) {
  208.     *height = mmc->minMax.max_height;
  209.     }
  210. }
  211.  
  212. static void ConstraintInitialize(req, new, args, num_args)
  213.     Widget req, new;
  214.     ArgList args;
  215.     Cardinal *num_args;
  216. {
  217.     MinMaxConstraint mmc = (MinMaxConstraint) new->core.constraints;
  218.     Dimension width = new->core.width, height = new->core.height;
  219. #define MAXDIM 32768
  220.  
  221.     if (mmc->minMax.min_width == -1 && mmc->minMax.max_width == -1) {
  222.     mmc->minMax.min_width = mmc->minMax.max_width = width;
  223.     }
  224.     if (mmc->minMax.min_height == -1 && mmc->minMax.max_height == -1) {
  225.     mmc->minMax.min_height = mmc->minMax.max_height = height;
  226.     }
  227.  
  228.     if (mmc->minMax.min_width == -1) mmc->minMax.min_width = 1;
  229.     if (mmc->minMax.max_width == -1) mmc->minMax.max_width = MAXDIM;
  230.     if (mmc->minMax.min_height == -1) mmc->minMax.min_height = 1;
  231.     if (mmc->minMax.max_height == -1) mmc->minMax.max_height = MAXDIM;
  232.  
  233.     CheckConstraint(new, &mmc->minMax.min_width,
  234.         &mmc->minMax.max_width, "width");
  235.     CheckConstraint(new, &mmc->minMax.min_height,
  236.         &mmc->minMax.max_height, "height");
  237.     ResizeWithinConstraints(new, &width, &height);
  238.  
  239.     if (width != new->core.width || height != new->core.height) {
  240.     XtResizeWidget(new, width, height);
  241.     }
  242. #undef MAXDIM
  243. }
  244.  
  245. static void CalculateNewSize(minMax, width, height)
  246.     MinMaxWidget minMax;
  247.     register Dimension *width, *height;
  248. {
  249.     register Widget child;
  250.     register int i;
  251.     int right, bottom;
  252.  
  253.     *width = *height = 0;
  254.  
  255.     for (i = 0; i < minMax->composite.num_children; i++) {
  256.         child = minMax->composite.children[i];
  257.     if (!XtIsManaged(child)) continue;
  258.     right = child->core.x + child->core.width +
  259.         2 * child->core.border_width;
  260.     bottom = child->core.y + child->core.height +
  261.         2 * child->core.border_width;
  262.     if (right > (int) *width) *width = right;
  263.     if (bottom > (int) *height) *height = bottom;
  264.     }
  265.  
  266.     *width += minMax->minMax.margin;
  267.     *height += minMax->minMax.margin;
  268.  
  269.     if (*width == 0) *width = 1;
  270.     if (*height == 0) *height = 1;
  271. }
  272.  
  273. static void ResizeChildren(minMax, initiator)
  274.     MinMaxWidget minMax;
  275.     Widget initiator;
  276. {
  277.     register Widget child;
  278.     register MinMaxConstraint mmc;
  279.     register int i;
  280.     int right, bottom;
  281.     int new_width, new_height;
  282.     int minMax_right = minMax->core.width - minMax->minMax.margin,
  283.     minMax_bottom = minMax->core.height - minMax->minMax.margin;
  284.  
  285.     for (i = 0; i < minMax->composite.num_children; i++) {
  286.         child = minMax->composite.children[i];
  287.     if (!XtIsManaged(child) || child == initiator) continue;
  288.  
  289.     mmc = (MinMaxConstraint) child->core.constraints;
  290.     new_width = child->core.width;
  291.     new_height = child->core.height;
  292.  
  293.     right = child->core.x + child->core.width +
  294.         2 * child->core.border_width;
  295.     bottom = child->core.y + child->core.height +
  296.         2 * child->core.border_width;
  297.  
  298.     if (right > minMax_right &&
  299.         child->core.width > mmc->minMax.min_width) {
  300.         new_width -= right - minMax_right;
  301.         if (new_width < mmc->minMax.min_width) {
  302.         new_width = mmc->minMax.min_width;
  303.         }
  304.     } else if (right < minMax_right &&
  305.         child->core.width < mmc->minMax.max_width) {
  306.         new_width += minMax_right - right;
  307.         if (new_width > mmc->minMax.max_width) {
  308.         new_width = mmc->minMax.max_width;
  309.         }
  310.     }
  311.  
  312.     if (bottom > minMax_bottom &&
  313.         child->core.height > mmc->minMax.min_height) {
  314.         new_height -= bottom - minMax_bottom;
  315.         if (new_height < mmc->minMax.min_height) {
  316.         new_height = mmc->minMax.min_height;
  317.         }
  318.     } else if (bottom < minMax_bottom &&
  319.         child->core.height < mmc->minMax.max_height) {
  320.         new_height += minMax_bottom - bottom;
  321.         if (new_height > mmc->minMax.max_height) {
  322.         new_height = mmc->minMax.max_height;
  323.         }
  324.     }
  325.  
  326.     XtResizeWidget(child, new_width, new_height,
  327.         child->core.border_width);
  328.     }
  329. }
  330.  
  331. static void Resize(w)
  332.     Widget w;
  333. {
  334.     ResizeChildren((MinMaxWidget) w, (Widget) NULL);
  335. }
  336.  
  337. static void ChangeManaged(w)
  338.     Widget w;
  339. {
  340.     MinMaxWidget minMax = (MinMaxWidget) w;
  341.     XtWidgetGeometry request;
  342.     XtGeometryResult result;
  343.  
  344.     CalculateNewSize(minMax, &request.width, &request.height);
  345.  
  346.     if (request.width != minMax->core.width ||
  347.         request.height != minMax->core.height) {
  348.     request.request_mode = CWWidth | CWHeight;
  349.     do {
  350.         result = XtMakeGeometryRequest(w,
  351.             &request, (XtWidgetGeometry *) NULL);
  352.     } while (result == XtGeometryAlmost);
  353.  
  354.     if (result == XtGeometryYes) {
  355.         ResizeChildren(minMax, (Widget) NULL);
  356.     }
  357.     }
  358. }
  359.  
  360. static XtGeometryResult GeometryManager(w, desired, allowed)
  361.     Widget w;
  362.     XtWidgetGeometry *desired, *allowed;
  363. {
  364.     MinMaxWidget minMax = (MinMaxWidget) XtParent(w);
  365.     MinMaxConstraint mmc = (MinMaxConstraint) w->core.constraints;
  366.     XtWidgetGeometry request;
  367.     XtGeometryResult result;
  368.     Dimension save_width, save_height, save_border_width;
  369.     Position save_x, save_y;
  370.  
  371. #define Wants(flag) (desired->request_mode & flag)
  372. #define RestoreGeometry(w) { \
  373.     w->core.x = save_x;        w->core.y = save_y; \
  374.     w->core.width = save_width; w->core.height = save_height; \
  375.     w->core.border_width = save_border_width; }
  376.  
  377.     /* If the desired change goes outside the constraints, say no */
  378.  
  379.     if ((Wants(CWWidth) && (desired->width < mmc->minMax.min_width ||
  380.             desired->width > mmc->minMax.max_width)) ||
  381.         (Wants(CWHeight) &&
  382.             (desired->height < mmc->minMax.min_height ||
  383.             desired->height > mmc->minMax.max_height))) {
  384.     return XtGeometryNo;
  385.     }
  386.  
  387.     /* Figure out how big we would be with this change */
  388.  
  389.     save_x = w->core.x;
  390.     save_y = w->core.y;
  391.     save_width = w->core.width;
  392.     save_height = w->core.height;
  393.     save_border_width = w->core.border_width;
  394.     if (Wants(CWX)) w->core.x = desired->x;
  395.     if (Wants(CWY)) w->core.y = desired->y;
  396.     if (Wants(CWWidth)) w->core.width = desired->width;
  397.     if (Wants(CWHeight)) w->core.height = desired->height;
  398.     if (Wants(CWBorderWidth)) {
  399.     w->core.border_width = desired->border_width;
  400.     }
  401.  
  402.     CalculateNewSize(minMax, &request.width, &request.height);
  403.  
  404.     if (request.width == minMax->core.width && 
  405.         request.height == minMax->core.height) {
  406.     if (Wants(XtCWQueryOnly)) RestoreGeometry(w);
  407.     return XtGeometryYes;
  408.     }
  409.  
  410.     /* We need to change size in order to accommodate; see if we can */
  411.  
  412.     request.request_mode = CWWidth | CWHeight;
  413.     if (Wants(XtCWQueryOnly)) request.request_mode |= XtCWQueryOnly;
  414.  
  415.     result = XtMakeGeometryRequest((Widget) minMax, &request, NULL);
  416.     if (result == XtGeometryAlmost) result = XtGeometryNo;
  417.  
  418.     if (result == XtGeometryYes && !Wants(XtCWQueryOnly)) {
  419.     ResizeChildren(minMax, w);
  420.     return XtGeometryYes;
  421.     }
  422.  
  423.     /* Undo the saved changes */
  424.  
  425.     RestoreGeometry(w);
  426.     return result;
  427. #undef Wants
  428. #undef RestoreGeometry
  429. }
  430.  
  431. static Boolean SetValues(old, req, new, args, num_args)
  432.     Widget old, req, new;
  433.     ArgList args;
  434.     Cardinal *num_args;
  435. {
  436.     register MinMaxWidget oldminMax = (MinMaxWidget) old;
  437.     register MinMaxWidget newminMax = (MinMaxWidget) new;
  438.  
  439.     if (newminMax->minMax.margin != oldminMax->minMax.margin ||
  440.         newminMax->core.width == 0 ||
  441.         newminMax->core.height == 0) {
  442.     CalculateNewSize(newminMax,
  443.         &newminMax->core.width, &newminMax->core.height);
  444.     }
  445.  
  446.     return FALSE;
  447. }
  448.  
  449. static Boolean ConstraintSetValues(old, req, new, args, num_args)
  450.     Widget old, req;
  451.     ArgList args;
  452.     Cardinal *num_args;
  453.     register Widget new;
  454. {
  455.     register MinMaxConstraint mmc = 
  456.         (MinMaxConstraint) new->core.constraints;
  457.  
  458.     CheckConstraint(new, &mmc->minMax.min_width,
  459.         &mmc->minMax.max_width, "width");
  460.     CheckConstraint(new, &mmc->minMax.min_height,
  461.         &mmc->minMax.max_height, "height");
  462.     ResizeWithinConstraints(new, &new->core.width, &new->core.height);
  463.  
  464.     return FALSE;
  465. }
  466.  
  467. static Boolean AcceptFocus(w, time)
  468.     Widget w;
  469.     Time *time;
  470. {
  471.     MinMaxWidget minMax = (MinMaxWidget) w;
  472.     register int i;
  473.  
  474.     if (minMax->minMax.last_focus != NULL && 
  475.         XtIsManaged(minMax->minMax.last_focus)) {
  476.     if (XtCallAcceptFocus(minMax->minMax.last_focus, time)) {
  477.         return TRUE;
  478.     }
  479.     }
  480.  
  481.     for (i = 0; i < minMax->composite.num_children; i++) {
  482.     if (!XtIsManaged(minMax->composite.children[i])) continue;
  483.     if (XtCallAcceptFocus(minMax->composite.children[i], time)) {
  484.         minMax->minMax.last_focus = minMax->composite.children[i];
  485.         return TRUE;
  486.     }
  487.     }
  488.  
  489.     minMax->minMax.last_focus = NULL;
  490.     return FALSE;
  491. }
  492.  
  493. static void Redisplay(w, event, region)
  494.     Widget w;
  495.     XEvent *event;
  496.     Region region;
  497. {
  498.     CompositeWidget comp = (CompositeWidget) w;
  499.     int i;
  500.     Widget c;        /* child */
  501.  
  502.     for (i = 0; i < comp->composite.num_children; i++) {
  503.     c = comp->composite.children[i];
  504.     if (XtIsManaged(c) && XtIsSubclass(c, labelGadgetClass) &&
  505.         XRectInRegion(region, c->core.x, c->core.y,
  506.             c->core.width + 2*c->core.border_width,
  507.             c->core.height + 2*c->core.border_width)
  508.             != RectangleOut) {
  509.         (*(XtClass(c)->core_class.expose))(c, event, region);
  510.         }
  511.     }
  512. }
  513.