.\"remove .ig hn for full docs .de hi .ig eh .. .de eh .. .TH "" 3 "" "Version 3.0" "Free Widget Foundation" .SH NAME XfwfBoard .SH DESCRIPTION The Board class adds one thing to the capabilities already present in the Frame class, viz., location management. Location management is an improved version of the standard X geometry management. Size and position of a Board widget (or subclass) can be given as a combination of absolute and relative sizes. In contrast to its superclass Frame, Board accepts any number of children. No layout policy is enforced, however. The children are expected to be positioned with the help of their own geometry or location resources. .SS "Public variables" .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. XfwfBoard Name Class Type Default XtNabs_x XtCAbs_x Position 0 XtNrel_x XtCRel_x Float "0.0" XtNabs_y XtCAbs_y Position 0 XtNrel_y XtCRel_y Float "0.0" XtNabs_width XtCAbs_width Position 0 XtNrel_width XtCRel_width Float "1.0" XtNabs_height XtCAbs_height Position 0 XtNrel_height XtCRel_height Float "1.0" XtNhunit XtCHunit Float "1.0" XtNvunit XtCVunit Float "1.0" XtNlocation XtCLocation String NULL .TE .ps The location management relies on a total of ten resources plus a string resource that combines eight of them in a more convenient and compact notation. The location is given by two values in each of the four dimensions (x, y, width and height). One value holds the absolute position in pixels, the other holds the position relative to the parent's width. E.g., When \fIabs_x\fP is 20 and \fIrel_x\fP is 0.3, the x position of the widget will be 20 pixels plus 0.3 times the width of the parent. For more examples, see the \fIlocation\fP resource below. The ninth and tenth resources are \fIhunit\fP and \fIvunit\fP. All assignments to the \fIabs_*\fP resources are multiplied by \fIhunit\fP (horizontal) or \fIvunit\fP (vertical). Normally the units are 1, but, e.g., a widget that displays text might set them to the width and height of character cells, so that \fIabs_width = 80\fP means a width of 80 characters, instead of 80 pixels. The geometry resources of the Core widget (\fIx\fP, \fIy\fP, \fIwidth\fP and \fIheight\fP are still available. When they are set, the values are copied to the \fIabs_*\fP variables and the \fIrel_*\fP variables are set to 0.0. It is possible that the parent of the current widget doesn't grant the preferred geometry. In that case the location variables and the geometry variables will not be synchronized. The location variables will then be taken to hold the preferred geometry, instead of the actual one. .TP .I "XtNabs_x" The position is determined by the four resources \fIabs_x\fP, \fIrel_x\fP, \fIabs_y\fP and \fIrel_y\fP. When the parent is (a subclass of) a Board widget, the position is not measured from the real size of the parent, but from the size inside the frame. (The representation of the float values as strings seems necessary, because the compiler can't cast a float to a pointer.) .hi .nf Position abs_x = 0 .fi .eh .TP .I "XtNrel_x" .hi .nf float rel_x = "0.0" .fi .eh .TP .I "XtNabs_y" .hi .nf Position abs_y = 0 .fi .eh .TP .I "XtNrel_y" .hi .nf float rel_y = "0.0" .fi .eh .TP .I "XtNMAGICNUM" By setting default values for the \fIx\fP and \fIy\fP variables from Core explicitly, we can be sure that the variables are synchronized from the start. If the \fIinitialize\fP method detects a change in any of them, it can re-synchronize them. .hi .nf MAGICNUM = .fi .eh .TP .I "XtNx" .hi .nf x = MAGICNUM .fi .eh .TP .I "XtNy" .hi .nf y = MAGICNUM .fi .eh .TP .I "XtNabs_width" The default values cause a Board widget to be the same size as it's parent at all times, provided, of course, that the parent allows that. If the parent is (a subclass of) a Board widget, the size is relative to the area inside the parent's frame, instead of the total size of the parent. .hi .nf Position abs_width = 0 .fi .eh .TP .I "XtNrel_width" .hi .nf float rel_width = "1.0" .fi .eh .TP .I "XtNabs_height" .hi .nf Position abs_height = 0 .fi .eh .TP .I "XtNrel_height" .hi .nf float rel_height = "1.0" .fi .eh .TP .I "XtNwidth" The Core variables are given strange defaults, in the hope that the \fIinitialize\fP method can detect a change in them. .hi .nf width = MAGICNUM .fi .eh .TP .I "XtNheight" .hi .nf height = MAGICNUM .fi .eh .TP .I "XtNhunit" \fIhunit\fP is a value in pixels by which \fIabs_x\fP and \fIabs_width\fP are multiplied; \fIabs_y\fP and \fIabs_height\fP are multiplied by \fIvunit\fP. The results are rounded to the next larger whole number. .hi .nf float hunit = "1.0" .fi .eh .TP .I "XtNvunit" .hi .nf float vunit = "1.0" .fi .eh .TP .I "XtNlocation" Specifying eight resources in a resource file is more easily done with the string resource \fIlocation\fP. The string contains four expressions of the form $x_a\pm x_r$ or $x_r\pm x_a$ or $x_a$ or $x_r$, where $x_a$ is the absolute value and $x_r$ is the relative value. The two are distinguished by the fact that $x_r$ {\em must} contain a decimal point. Examples: \fI"0.5 - 20 5 40 1.0 - 50"\fP is a widget of fixed width (40 units) that is horizontally centered; the height is always 50 units less than the height of the parent. \fI"0 0 2.0 3.0"\fP is a widget that is twice as wide and three times as high as its parent. \fI"-20 0 20 20"\fP is a widget that will be invisible, because it is located 20 units to the left of the parent and it is also 20 units wide. The initial value is \fINULL\fP, but the \fIinitialize\fP method will make sure that the string is synchronized with the other variables. .hi .nf String location = NULL .fi .eh .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. XfwfFrame Name Class Type Default XtNcursor XtCCursor Cursor None XtNframeType XtCFrameType FrameType XfwfRaised XtNframeWidth XtCFrameWidth Dimension 0 XtNouterOffset XtCOuterOffset Dimension 0 XtNinnerOffset XtCInnerOffset Dimension 0 XtNshadowScheme XtCShadowScheme ShadowScheme XfwfAuto XtNtopShadowColor XtCTopShadowColor Pixel compute_topcolor XtNbottomShadowColor XtCBottomShadowColor Pixel compute_bottomcolor XtNtopShadowStipple XtCTopShadowStipple Bitmap NULL XtNbottomShadowStipple XtCBottomShadowStipple Bitmap NULL .TE .ps .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. XfwfCommon Name Class Type Default XtNtraversalOn XtCTraversalOn Boolean True XtNhighlightThickness XtCHighlightThickness Dimension 2 XtNhighlightColor XtCHighlightColor Pixel XtDefaultForeground XtNhighlightPixmap XtCHighlightPixmap Pixmap None XtNnextTop XtCNextTop Callback NULL XtNuserData XtCUserData Pointer NULL .TE .ps .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. Composite Name Class Type Default XtNchildren XtCChildren WidgetList NULL insertPosition XtCInsertPosition XTOrderProc NULL numChildren XtCNumChildren Cardinal 0 .TE .ps .ps-2 .TS center box; cBsss lB|lB|lB|lB l|l|l|l. Core Name Class Type Default XtNx XtCX Position 0 XtNy XtCY Position 0 XtNwidth XtCWidth Dimension 0 XtNheight XtCHeight Dimension 0 borderWidth XtCBorderWidth Dimension 0 XtNcolormap XtCColormap Colormap NULL XtNdepth XtCDepth Int 0 destroyCallback XtCDestroyCallback XTCallbackList NULL XtNsensitive XtCSensitive Boolean True XtNtm XtCTm XTTMRec NULL ancestorSensitive XtCAncestorSensitive Boolean False accelerators XtCAccelerators XTTranslations NULL borderColor XtCBorderColor Pixel 0 borderPixmap XtCBorderPixmap Pixmap NULL background XtCBackground Pixel 0 backgroundPixmap XtCBackgroundPixmap Pixmap NULL mappedWhenManaged XtCMappedWhenManaged Boolean True XtNscreen XtCScreen Screen * NULL .TE .ps .hi .SH "Importss" .nf .B incl .fi .nf .B incl .fi .nf .B incl .fi .hi .hi .SS "Methods" Changes in the location resources result in changes in the core geometry resources. If the location resources didn't change, but the core geometry resources did, the location variables are set accordingly. If various resources are changes at the same time, \fIlocation\fP takes precedence, followed by the \fIabs_*\fP and \fIrel_*\fP variables, and finally the core geometry variables \fIx\fP, \fIy\fP, \fIwidth\fP and \fIheight\fP. \fIset_values\fP takes care that all these resources always correspond to each other; even the \fIlocation\fP string is re-generated when any of the others change. Since the location is handled by setting the core geometry resources, there is never any need to redraw the widget. A complication arises when the frame of the Board widget changes, since children may have sizes that are relative to the area inside the frame. The Board widget therefore gives its children a chance to calculate their new locations in this case. .nf Boolean set_values(Widget old, Widget request, $, ArgList args, Cardinal * num_args) { XtWidgetGeometry reply; int i; if ($location != $old$location) { XtFree($old$location); $location = XtNewString($location); interpret_location($); get_core_geometry($, $x, $y, $width, $height); } else if (ceil($abs_x*$hunit) != ceil($old$abs_x*$old$hunit) || ceil($abs_width*$hunit) != ceil($old$abs_width*$old$hunit) || ceil($abs_y*$vunit) != ceil($old$abs_y*$old$vunit) || ceil($abs_height*$vunit) != ceil($old$abs_height*$old$vunit) || $rel_x != $old$rel_x || $rel_y != $old$rel_y || $rel_width != $old$rel_width || $rel_height != $old$rel_height) { get_core_geometry($, $x, $y, $width, $height); generate_location($); } else if ($x != $old$x || $y != $old$y || $width != $old$width || $height != $old$height) { set_location($, CWX | CWY | CWWidth | CWHeight); generate_location($); } if ($highlightThickness + $frameWidth + $outerOffset + $innerOffset != $old$highlightThickness + $old$frameWidth + $old$outerOffset + $innerOffset) { for (i = 0; i < $num_children; i++) { (void) XtQueryGeometry($children[i], NULL, reply); XtConfigureWidget($children[i], reply.x, reply.y, reply.width, reply.height, reply.border_width); } } return False; } .fi The initialize method is used to synchronize the location and geometry resources for the first time. It is difficult to find out which variables have been set from resources and which still have their initial value, we rely on the fact that the default value is unlikely to be used in practice. If the \fIlocation\fP string has been set, it will be used to set all other variables. If the Core geometry resources have been set, we use them, otherwise, the location variables will determine the size and position. .nf initialize(Widget request, $, ArgList args, Cardinal * num_args) { if ($location != NULL) { $location = XtNewString($location); interpret_location($); get_core_geometry($, $x, $y, $width, $height); } else if ($x != MAGICNUM || $y != MAGICNUM || $width != MAGICNUM || $height != MAGICNUM) { set_location($, CWX | CWY | CWWidth | CWHeight); generate_location($); } else { generate_location($); get_core_geometry($, $x, $y, $width, $height); } } .fi The \fIset_abs_location\fP method is a convenience function for use by subclasses. When they want to set the \fIx\fP, \fIy\fP, \fIwidth\fP or \fIheight\fP resources, they can call this function which will than also adjust the other location resources accordingly. The flags determine which resources are set, it is a bitwise combination of \fICWX\fP, \fICWY\fP, \fICWWidth\fP and \fICWHeight\fP. .nf set_abs_location($, unsigned int flags, int x, int y, int w, int h) { if (flags (CWX | CWY | CWWidth | CWHeight) == 0) return; if (flags CWX) $x = x; if (flags CWY) $y = y; if (flags CWWidth) $width = w; if (flags CWHeight) $height = h; set_location($, flags); generate_location($); } .fi The \fIresize\fP method is called when the widget is resized. The children of the Board widget will be given a chance to re-compute their preferred locations, which will then be granted them. It may be possible that the parent of the current widget didn't grant the preferred geometry. In that case the geometry variables will be different from the location variables. The latter will not be changed, in the hope that the requested geometry can be set later. .nf resize($) { int i; XtWidgetGeometry reply; Widget child; for (i = 0; i < $num_children; i++) { child = $children[i]; (void) XtQueryGeometry(child, NULL, reply); XtConfigureWidget(child, reply.x, reply.y, reply.width, reply.height, reply.border_width); } } .fi When the Board's parent asks for this widget's preferred geometry, simply return the geometry as indicated by the location variables. Currently, the method always returns \fIXtGeometryAlmost\fP. It doesn't bother to check if the preferred geometry is equal to the current geometry (in which case it should really return \fIXtGeometryNo\fP) or if the preferred geometry is equal to what the parent proposed (in which case a return of \fIXtGeometryYes\fP should have been given. It seems that no harm is done by always returning \fIXtGeometryAlmost\fP and letting Xt figure out what really needs to be changed. .nf XtGeometryResult query_geometry($, XtWidgetGeometry * request, XtWidgetGeometry * reply) { reply->request_mode = CWX | CWY | CWWidth | CWHeight; get_core_geometry($, reply->x, reply->y, reply->width, reply->height); return XtGeometryAlmost; } .fi If a child requests to be resized, the request is always granted. We ignore stacking order. .nf XtGeometryResult geometry_manager(Widget child, XtWidgetGeometry * request, XtWidgetGeometry * reply) { Widget $ = XtParent(child); Dimension wd, ht, bw; Position x, y; /* Get complete geometry, from request or current value */ x = request->request_mode CWX ? request->x : $child$x; y = request->request_mode CWY ? request->y : $child$y; wd = request->request_mode CWWidth ? request->width : $child$width; ht = request->request_mode CWHeight ? request->height : $child$height; bw = request->request_mode CWBorderWidth ? request->border_width : $child$border_width; XtConfigureWidget(child, x, y, wd, ht, bw); return XtGeometryDone; } .fi If a child becomes managed or unmanaged, the Board widget is given a change to resize or reposition the child. The Board widget doesn't do that, but it does install all accelerators of its descendants here. .nf change_managed($) { Widget top = $, w; while (! XtIsSubclass(top, shellWidgetClass)) top = XtParent(top) ; for (w = $; w != top; w = XtParent(w)) XtInstallAllAccelerators(w, top); } .fi .hi .hi .SH "Utilities" \fBdef\fP ceil(r) = (-(int )(-(r ))) The routine \fIgenerate_location\fP creates the string \fIlocation\fP from the values of the location resources. .nf generate_location($) { char tmp[100]; (void) sprintf(tmp, "%d+%f %d+%f %d+%f %d+%f", $abs_x, $rel_x, $abs_y, $rel_y, $abs_width, $rel_width, $abs_height, $rel_height); XtFree($location); $location = XtNewString(tmp); } .fi To get the core geometry from the location variables, the function \fIget_core_geometry\fP is used. It combines the relative and absolute parts of the location and sets the result in the passed variables. When the parent is a Board widget or a subclass thereof, the area inside the parent's frame is used for calculations, otherwise the whole area of the parent will be used. As a safeguard against possible non-positive sizes, the width and height cannot become smaller than 1 pixel. .nf get_core_geometry($, Position * x, Position * y, Dimension * width, Dimension * height) { Widget parent; Position px, py; Dimension pw, ph; float h; parent = $parent; if (XtIsSubclass($parent, xfwfBoardWidgetClass)) $parent$compute_inside(parent, px, py, pw, ph); else { px = 0; py = 0; pw = $parent$width; ph = $parent$height; } *x = ceil($rel_x * pw + $abs_x * $hunit) + px; *y = ceil($rel_y * ph + $abs_y * $vunit) + py; h = ceil($rel_width * pw + $abs_width * $hunit); *width = h < 1.0 ? 1 : h; h = ceil($rel_height * ph + $abs_height * $vunit); *height = h < 1.0 ? 1 : h; } .fi The reverse operation, computing the location variables from the core geometry is done by \fIset_location\fP. .nf set_location($, unsigned int flags) { Widget parent; Position px, py; Dimension pw, ph; parent = $parent; if (XtIsSubclass($parent, xfwfBoardWidgetClass)) $parent$compute_inside(parent, px, py, pw, ph); else { px = 0; py = 0; pw = $parent$width; ph = $parent$height; } if (flags CWX) { $rel_x = 0.0; $abs_x = ceil(($x - px)/$hunit); } if (flags CWY) { $rel_y = 0.0; $abs_y = ceil(($y - py)/$vunit); } if (flags CWWidth) { $rel_width = 0.0; $abs_width = ceil($width/$hunit); } if (flags CWHeight) { $rel_height = 0.0; $abs_height = ceil($height/$vunit); } } .fi Interpreting the \fIlocation\fP string is a little harder, but still straightforward. Only numbers (with or without decimal points) and plus and minus signs can appear in the string. \fIscan\fP recognizes four formats: an integer followed by a plus or minus and a float, a float followed by a plus or minus and an integer, a single integer, or a single float. \fBdef\fP skip_blanks(s) = while (isspace (*s ))s ++ .nf char * scan(char * s, Position * absval, float * relval) { Position n; char *t; Boolean minus; *absval = 0; *relval = 0.0; n = strtol(s, t, 0); if (*t != '.') { /* Found an integer */ *absval = n; s = t; skip_blanks(s); if (*s != '+' *s != '-') return s; /* Nothing follows */ n = strtol(s + 1, t, 0); if (*t != '.') return s; /* It's not a float */ minus = (*s == '-'); *relval = strtod(s + 1, s); /* Found a float */ if (minus) *relval = - *relval; return s; } else { /* Found a float */ *relval = strtod(s, s); skip_blanks(s); if (*s != '+' *s != '-') return s; /* Nothing follows */ n = strtol(s + 1, t, 0); if (*t == '.') return s; /* It's not an integer */ if (*s == '-') *absval = -n; else *absval = n; return t; } } .fi .nf interpret_location($) { char *s, *t; s = $location; s = scan(s, $abs_x, $rel_x); s = scan(s, $abs_y, $rel_y); s = scan(s, $abs_width, $rel_width); s = scan(s, $abs_height, $rel_height); } .fi .hi