One of the more difficult aspects of programming a graphically oriented application is positioning the user interface components on the screen. Developers often have to manually place buttons, size dialog boxes, and draw frames and titles. The GEOS Geometry Manager lets you ignore most of these issues.
The geometry manager allows you to ignore position, size, and spacing of your generic UI components; if you use visual objects, the geometry manager can calculate object sizes and positions, dynamically changing them as necessary. Because the geometry manager works at run-time, you have to do very little in the way of screen management. Instead, you can set various attributes and hints to fine-tune your UI's appearance.
1 Geometry Manager Overview
1.1 Geometry Manager Features
1.2 How Geometry Is Managed
2 Arranging Your Generic Objects
2.1 General Geometry Rules
2.2 Orienting Children
2.3 Justifying and Centering Children
2.4 Sizing Objects
2.5 Outlining the Composite
2.6 Using Monikers
2.7 Using Custom Child Spacing
2.8 Allowing Children to Wrap
2.9 Object Placement
3 Positioning and Sizing Windows
3.1 Window Positioning
3.2 Determining Initial Size
3.3 On-Screen Behavior
3.4 Window Look and Feel
The GEOS geometry manager is an algorithmic mechanism which interacts directly with the UI to position and size objects of all types. The geometry manager automatically manages all generic objects through interactions with the specific UI library; you can also use it to manage your visible object trees.
The Geometry Manager is what makes the generic UI possible: Since geometry of UI objects (size and position) is determined by the UI at run-time, generic UI objects do not have to be explicitly defined with certain geometry. With this feature, a specific UI library can set up the UI geometry as it wants.
Your first interaction with the geometry manager will be when you build a generic object tree for your UI. Most hints applied to an object are signals to the geometry manager about how the object should be positioned, sized, or otherwise placed on the screen. These hints are all defined in
GenClass
, the topmost generic object class, so they are available (though not necessarily useful) to all types of generic objects.
This chapter first describes the features of the geometry manager and how the mechanism fits into the GEOS system as a whole (later in this section). Then it discusses how to manage generic UI objects (using a dialog box as an example) in Arranging Your Generic Objects . For the hints you can apply to window objects, see Positioning and Sizing Windows . For descriptions of managing the geometry of visible object trees and composites, see the VisClass chapter.
The geometry manager, used effectively, can take nearly all the work out of displaying, sizing, and positioning objects on the screen. Many of the tasks you normally would have to do to create even a simple dialog box are taken care of automatically by the geometry manager and the specific UI library. Among the functions the geometry manager performs are the following:
With geometry functions covered by the geometry manager and drawing functions covered by the specific UI library, you have little else to do but specify the structure of your object tree and the hints each object should have. The system does all the dirty work of drawing and managing the objects on the screen, leaving you free to work on your application rather than on its graphical screen representation.
The geometry manager is one part of the system that draws objects on the screen and redraws them when necessary. This system is called the "visual update mechanism."
The visual update mechanism is invoked any time the geometry or image of an object is marked invalid. If only the image is invalid, typically no geometry calculations will be done. If, however, the geometry of an object is marked invalid, the geometry manager is called in to calculate the new size and position of all the affected objects in the object tree.
Normally, you won't have to do any more than set certain hints (for generic objects) or attribute flags (for visible objects) to get the desired geometry behavior. If, however, you plan on modifying how the geometry of a particular set of objects is set, you will want to understand the sequence of events that happen during a geometry update. Typically, only programmers who are building their own specific UI libraries and those who have complex visual object trees will need to understand the geometry calculation sequence.
The geometry manager's calculation can be thought of as a multiple-pass, recursive algorithm. It traverses the object tree, managing geometry within each composite until it reaches the top-most object that is unaffected by the geometry calculations.
The geometry update process is invoked when an object has its geometry marked invalid. This is determined by the object's visual flags (its
VI_optFlags
field), VOF_GEOMETRY_INVALID and VOF_WINDOW_INVALID. If either of these flags is set, the object's geometry requires recalculation.
The geometry manager sends
MSG_VIS_UPDATE_GEOMETRY
to the visible object with invalid geometry. This message determines which objects in the tree are potentially affected by the geometry update, and then it recalculates the tree's geometry.
If the object initially marked invalid is a composite, all its children are automatically included in the update. If the object is a child of a composite, the geometry manager will travel up the tree, marking any parents and siblings that also require recalculation. (Recalculation does not cross VTF_IS_WIN_GROUP boundaries, however. A VTF_IS_WIN_GROUP is any windowed object; geometry calculations generally do not cross windowed objects (move into another window layer) unless explicitly instructed to do so.)
The geometry manager then returns to the bottom-most affected object in the tree and sends it a
MSG_VIS_RECALC_SIZE
. This message passes the object a suggested size, which will be the same as the object's original size. (The original size is passed as an optimization in case the object does not need its geometry changed; many changes will affect many objects but will actually change only a few.)
The object then returns its new desired size based on the geometry change. If this is the original object marked invalid, the returned size will be the direct result of the geometry change. If this object is a descendent of the invalid object, it may not want to change its geometry at all and may therefore return its current size.
The geometry manager collects the returned sizes of all siblings at a given level and calculates the suggested size of their parent composite. The parent composite is then sent
MSG_VIS_RECALC_SIZE
with the newly calculated size and returns the size it wants to be as a result. (Some composites will have fixed, maximum, or minimum sizes or may have their sizing tied to other factors; these objects may return a different size.) If the returned size is different from the passed size, the geometry manager arbitrates between the objects. Typically, the composite will be grown large enough (even if fixed or maximum size) to fit all its children.
The geometry manager will go up the tree in this manner, calculating the new geometry of each child and then each composite until it reaches an object that is unaffected by the geometry change. (For example, if a child shrinks but other children cause the composite to remain the same size, the geometry update will stop at the composite because objects higher up are not affected.) If all objects in the tree are affected by the change, the geometry update will stop at the topmost object in the branch (the first VTF_IS_WIN_GROUP object).
If any parent objects disagree with their children on the new size, the geometry manager will arbitrate. The geometry manager may make several passes to suggest width and height changes to both the child and parent before deciding on an ultimate geometry. The geometry manager may alter child spacing, wrap the children, grow the composite, or even clip the children if necessary. A result will quickly be reached, however--the geometry manager will not thrash between the parent and children (unless you subclass
MSG_VIS_RECALC_SIZE
or
MSG_VIS_GET_CENTER
and do not pay close attention to how the message is handled).
After the geometry is recalculated up to the first VTF_IS_WIN_GROUP object (or up to the top affected object), a
MSG_VIS_NOTIFY_GEOMETRY_VALID
will be sent to each of the invalid objects that have
VGA_NOTIFY_GEOMETRY_VALID set in their
VI_attrs
field. A visual update will then be started to draw the new geometry to the screen. Once a branch's geometry has been calculated, the branch will remain unaffected until the next time the geometry of one of its objects is marked invalid.
If a recalculation of a branch's geometry causes a VTF_IS_WIN_GROUP object to change its size or position, the window system will determine the effects. For example, if a VisContent object grows as a result of a geometry change, it will send a
MSG_GEN_VIEW_SET_DOC_BOUNDS
to the GenView; the geometry recalculation mechanism will not scroll the content-view connection. What happens to the view and its parent window then depends on the attributes of the view. For example, if the view is set to follow the size of its content, it will grow, bumping the size of its parent in the process. If the view is scrollable, it likely will stay the same size.
The process of arranging user interface elements for a GEOS application differs drastically from that of traditional user interface programming methods. In most graphical systems, you must manually determine the location of each and every user interface element. For instance, to design a dialog box, you have to figure the location of each text string, button, and list entry. Normally, these items would have to be hard-coded into your application, and often different video resolutions would have to be taken into account.
Not so in GEOS. The generic and specific UI libraries work with the geometry manager to automatically arrange your generic UI objects in the most appropriate way. To describe a dialog box in GEOS, for instance, you simply have to define the objects contained in the dialog box and their relative positions in the generic object tree; GEOS does the rest, determining the position and visual effects of each object. You can even fine-tune the appearance of each object with the use of hints.
Justifying and Centering Children
You may feel at first that the use of generic UI components limits your control over the UI of your application. Actually, just the opposite is true: Your application becomes immediately available at all supported video resolutions in all available specific UIs. Additionally, you can concentrate on more important issues of your application; the generic UI objects take care of a tremendous amount of the work in positioning and displaying the user interface.
To determine your generic UI tree, you must remember that UI geometry is determined by three things: First and foremost, the overall structure of the UI is governed by the structure and organization of the generic object tree. For example, if GenTriggers A, B, and C are designated as children of a dialog box, they will likely be ordered in the same order they're listed in the dialog's
GI_comp
field.
Second, an object's attributes can determine its implementation. For example, the
GIGI_visibility
field of a GenInteraction can determine whether the interaction is implemented as a dialog box, a menu, or a grouping object. The attributes of a generic object determine the basic functionality of the object; that is, even though a menu might be implemented differently in different specific UIs, the functionality of a menu will be implemented in the object. The manner of display of an object is based on its functionality. In this way, the attributes of a generic object take precedence over hints.
Third, an object's behavior can be fine-tuned through the use of hints. Hints may or may not be implemented for each object that has them, and they control less strictly how the object works.
As stated above, the structure of your application's generic object tree determines how the generic UI objects will be organized. A simple example of a generic tree including a menu, a dialog box, and a GenView can be found in the Hello World chapter.
Nearly all geometry of generic UI objects is determined by hints. You can position, size, and limit generic objects with different hints. All these hints are defined in
GenClass
; inheritance allows all generic objects to have them, though not all hints are applicable to all generic objects.
Hints are described in detail in the GenClass chapter, but the basics are reviewed here for convenience. Hints are implemented as variable data entries; each hint is a different variable-data type. Hints therefore take up instance data space in an object only when the object has that hint.
As stated earlier, not all hints are appropriate for all objects. For example,
HINT_CUSTOM_CHILD_SPACING
is probably not useful when applied to a GenTrigger object because a GenTrigger can have no children. Hints, by definition, are also not guaranteed to be supported by all specific UI libraries. For example, a specific UI might require all elements of a dialog box to be oriented horizontally; in this case,
HINT_ORIENT_CHILDREN_VERTICALLY
might be useful but might not be heeded by the specific UI.
Because geometry management of generic objects can be confusing at times, this chapter follows a series of examples accompanied with diagrams. For the most part, you should be able to "plug and play" the examples in the following sections.
HINT_ORIENT_CHILDREN_HORIZONTALLY, HINT_ORIENT_CHILDREN_VERTICALLY, HINT_ORIENT_CHILDREN_ALONG_LARGER_DIMENSION, HINT_SAME_ORIENTATION_AS_PARENT
The two hints
HINT_ORIENT_CHILDREN_HORIZONTALLY
and
HINT_ORIENT_CHILDREN_VERTICALLY
, when used in a composite object, determine the orientation of the composite's children. A composite object can orient its children either horizontally or vertically. The geometry manager will determine the combined size of the children and any margins or spacing set up (none by default) and will size the composite to the minimum required by its children.
Children oriented horizontally will typically be top-justified, and children oriented vertically will be left-justified. (This is default behavior changeable either with the use of hints or by the specific UI.) The vertical composite will size to the width of the widest child; the horizontal composite will size to the height of the tallest child.
Code Display 12-1 Orienting a Composite
/* Composite oriented horizontally */
@object GenInteractionClass MyInteraction = {
GI_comp = @ApplyTrigger, @ResetTrigger, @CancelTrigger;
HINT_ORIENT_CHILDREN_HORIZONTALLY;
}
/* Composite oriented vertically */
@object GenInteractionClass MyOtherInteraction = {
GI_comp = @ApplyTrigger, @ResetTrigger, @CancelTrigger;
HINT_ORIENT_CHILDREN_VERTICALLY;
}
A large example of a complex dialog box is shown in the figure below. This dialog box uses nested GenInteraction objects to achieve a complex grouping of children. Using the many justification, spacing, and orientation hints described throughout the chapter, you can change and fine-tune the appearance of the dialog box. The code that implements this dialog box is shown in A Complex Dialog Box
.
Two other hints may be useful for arranging children, especially in toolboxes. These two hints are not shown in the examples, though they are used prominently with tool groups.
HINT_SAME_ORIENTATION_AS_PARENT
is used by one windowed object (GenInteraction) when it should orient its children in the same way its parent does. This, too, is useful for toolboxes because you can set an orientation in the toolbox, then set
HINT_SAME_ORIENTATION_AS_PARENT
in the tool group.
HINT_ORIENT_CHILDREN_ALONG_LARGER_DIMENSION
allows you to orient a composite's children along the screen's larger dimension. The hint will work like
HINT_ORIENT_CHILDREN_HORIZONTALLY
if the screen is wider than it is tall; it will work like
HINT_ORIENT_CHILDREN_VERTICALLY
if the screen is taller than it is wide.
Code Display 12-2 A Complex Dialog Box
/* This code display shows the basic Goc code that will get the configuration * shown in the above figure. */
/* The topmost interaction. It groups the two large interactions vertically. */
@object GenInteractionClass TopInteraction = {
GI_comp = @ParaInteraction, @ReplyInteraction;
HINT_ORIENT_CHILDREN_VERTICALLY;
}
/* The top of the two large interactions. It groups the three smaller interactions
* on the top, horizontally. */
@object GenInteractionClass ParaInteraction = {
GI_comp = @FontInteraction, @JustInteraction, @StyleInteraction;
HINT_ORIENT_CHILDREN_HORIZONTALLY;
}
/* The interaction containing the Apply, Reset, and Cancel triggers. The
* triggers are oriented horizontally. */
@object GenInteractionClass ReplyInteraction = {
GI_comp = @ApplyTrigger, @ResetTrigger, @CancelTrigger;
HINT_ORIENT_CHILDREN_HORIZONTALLY;
}
/* The three vertically-oriented interactions at the top are similar. Each
* contains several triggers. All three are defined below. */
@object GenInteractionClass FontInteraction = {
GI_comp = @RomanTrigger, @SansTrigger, @MonoTrigger;
HINT_ORIENT_CHILDREN_VERTICALLY;
}
@object GenInteractionClass JustInteraction = {
GI_comp = @LeftTrigger, @RightTrigger, @CenterTrigger, @FullTrigger;
HINT_ORIENT_CHILDREN_VERTICALLY;
}
@object GenInteractionClass StyleInteraction = {
GI_comp = @PlainTrigger, @BoldTrigger, @SuperTrigger, @SubTrigger;
HINT_ORIENT_CHILDREN_VERTICALLY;
}
/* Triggers. All the triggers are essentially the same. Each is named as it * appears in the GI_comp fields above, and each has the corresponding * GI_visMoniker field. The RomanTrigger object is shown as an example. */
@object GenTriggerClass RomanTrigger = {
GI_visMoniker = "Roman";
}
Although child justification defaults to whatever the specific UI normally uses, you can set the justification of a composite's children with several different hints.
Typically, horizontal composites will have their children top-justified and vertical composites will have left-justified children (as shown in the previous examples).
HINT_TOP_JUSTIFY_CHILDREN, HINT_BOTTOM_JUSTIFY_CHILDREN, HINT_LEFT_JUSTIFY_CHILDREN, HINT_RIGHT_JUSTIFY_CHILDREN
If you want to line all of a composite's children up on one of their edges, you should use one of these hints. They are self-explanatory; the edge specified in the name of the hint (top, left, etc.) is the edge of the composite along which all the children will appear.
Add the justification hints along with an orientation hint. Examples of justification are shown in the figure below.
HINT_ALIGN_LEFT_EDGE_WITH_OBJECT, HINT_ALIGN_TOP_EDGE_WITH_OBJECT, HINT_ALIGN_RIGHT_EDGE_WITH_OBJECT, HINT_ALIGN_BOTTOM_EDGE_WITH_OBJECT
These hints align an object's respective edge with the same edge of another object; the optr of the other object is the hint's argument. The other object does not necessarily have to be a direct sibling or parent, but the result must not cause the object to stray outside its parent's bounds.
HINT_CENTER_CHILDREN_VERTICALLY, HINT_CENTER_CHILDREN_HORIZONTALLY
Often, rather than justifying a composite's children, you will want to center them. These two hints allow you to center the children as shown in the figure below.
HINT_FULL_JUSTIFY_CHILDREN_HORIZONTALLY, HINT_FULL_JUSTIFY_CHILDREN_VERTICALLY, HINT_DONT_FULL_JUSTIFY_CHILDREN, HINT_INCLUDE_ENDS_IN_CHILD_SPACING, HINT_DONT_INCLUDE_ENDS_IN_CHILD_SPACING
Besides justifying the composite's children either on a single edge or on the center line of the composite, you might want to full-justify the children. To do this, you will want to give the composite an orientation first (either vertical or horizontal). The composite may also require a special sizing hint to expand its bounds--see
HINT_EXPAND_WIDTH_TO_FIT_PARENT
and the other sizing hints in Sizing Objects
.
If the full justification hint is in the same dimension as the orientation of the composite (e.g.,
HINT_FULL_JUSTIFY_CHILDREN_HORIZONTALLY
and
HINT_ORIENT_CHILDREN_HORIZONTALLY
), then the geometry manager will divide up the entire space of the composite and spread the children out equally along it. If you also specify
HINT_INCLUDE_ENDS_IN_CHILD_SPACING
, the geometry manager will calculate the spacing as if there were one more child than there actually is; it will then put half the extra space on either end of the children. HINT_DONT_INCLUDE_ENDS_IN_CHILD_SPACING performs the default calculations. Examples of various full justification are shown in the figure below. See Using Full Justification of Children
for the code required to implement this full justification behavior.
Typically, full justification is not implemented by default. Some specific UIs may try to full-justify children always; if you want the children non-justified (when possible), apply
HINT_DONT_FULL_JUSTIFY_CHILDREN
. Added spacing is also typically not turned on by default; you can ensure that added spacing will not be included (where possible) by applying the hint
HINT_DONT_INCLUDE_ENDS_IN_CHILD_SPACING
to your composite.
Sizing can occur in essentially one of two ways: First, the composite can size itself based on its children. Second, the children can size themselves based on their parent. You can specify additional sizing restrictions in the form of minimum, maximum, and fixed sizes.
HINT_NO_TALLER_THAN_CHILDREN_REQUIRE, HINT_NO_WIDER_THAN_CHILDREN_REQUIRE
A composite can size itself to be only as large as its children require. This may be applied to your primary window or to other organizational composites to keep them from growing into any extra space in their parents. You can set the width and height restrictions independently; to set them both, use both hints in the composite.
HINT_EXPAND_HEIGHT_TO_FIT_PARENT, HINT_EXPAND_WIDTH_TO_FIT_PARENT, HINT_DIVIDE_WIDTH_EQUALLY, HINT_DIVIDE_HEIGHT_EQUALLY
Often a composite will have a set size and its children will want to expand themselves to take up all the available space. For example, the interaction with the Apply, Reset, and Cancel triggers in the dialog box (shown in the figure below) must have
HINT_EXPAND_WIDTH_TO_FIT_PARENT
set for it to expand itself to the far right edge of the dialog box. Another potential situation is a GenView within a GenPrimary; when the user resizes the primary, the view should probably expand itself to take up any extra space in the window.
A third example would be a series of triggers that want to be the same width in a vertical composite. This appears in many menus; each of the triggers expands itself to the width of the parent; the parent composite sizes its width to the largest of the triggers. An example taken from the complex dialog box is shown in the figure above. Code for this example is shown in Using Full Justification of Children .
Some more complex examples of expanding a group and justifying the elements are shown in the figure below. All of the examples use a justification hint combined with an expand-to-fit hint.
Code Display 12-3 Using Full Justification of Children
/* This code display shows the basic Goc code that will get the configuration * shown in the figure above. Other attributes are left out of the * definitions of the objects. This code display is supplemental to * A Complex Dialog Box; most comments have been removed. */
@object GenInteractionClass TopInteraction = {
GI_comp = @ParaInteraction, @ReplyInteraction;
HINT_ORIENT_CHILDREN_VERTICALLY;
}
@object GenInteractionClass ParaInteraction = {
GI_comp = @FontInteraction, @JustInteraction, @StyleInteraction;
HINT_ORIENT_CHILDREN_HORIZONTALLY;
}
@object GenInteractionClass ReplyInteraction = {
GI_comp = @ApplyTrigger, @ResetTrigger, @CancelTrigger;
HINT_ORIENT_CHILDREN_HORIZONTALLY;
HINT_EXPAND_WIDTH_TO_FIT_PARENT;
HINT_FULL_JUSTIFY_CHILDREN_HORIZONTALLY;
HINT_INCLUDE_ENDS_IN_CHILD_SPACING;
}
@object GenInteractionClass FontInteraction = {
GI_comp = @RomanTrigger, @SansTrigger, @MonoTrigger;
HINT_ORIENT_CHILDREN_VERTICALLY;
}
@object GenInteractionClass JustInteraction = {
GI_comp = @LeftTrigger, @RightTrigger, @CenterTrigger, @FullTrigger;
HINT_ORIENT_CHILDREN_VERTICALLY;
}
@object GenInteractionClass StyleInteraction = {
GI_comp = @PlainTrigger, @BoldTrigger, @SuperTrigger, @SubTrigger;
HINT_ORIENT_CHILDREN_VERTICALLY;
}
/* Triggers. All the upper triggers are essentially the same. Each is named as it * appears in the GI_comp fields above, and each has the corresponding * GI_visMoniker field. The RomanTrigger object is shown as an example. */
@object GenTriggerClass RomanTrigger = {
GI_visMoniker = "Roman";
HINT_EXPAND_WIDTH_TO_FIT_PARENT;
}
/* The Apply, Reset, and Cancel triggers do not have the hint shown above. */
@object GenTriggerClass ApplyTrigger = {
GI_visMoniker = "Apply";
}
HINT_DIVIDE_WIDTH_EQUALLY and HINT_DIVIDE_HEIGHT_EQUALLY instruct a composite object to divide up its space along the affected dimension among the usable children. This hint can only suggest sizes for the children. The children themselves will decide if they can expand or contract to fit the requested space. (In general, children will not contract to fit a requested size, but they may expand.) Note: these hints will not work within GenValue objects; if you wish to use them on such an object, place them within a dummy GenInteraction object and use these hints on that object.
Typically, these hints work well in conjunction with HINT_EXPAND_WIDTH_TO_FIT_PARENT and HINT_EXPAND_HEIGHT_TO_FIT_PARENT. If these hints are not also in place (on a GenInteraction, for example) the division of width and/or height may be based on the children's default size; i.e., the parent will size itself based on total size of the children and then attempt to divide up its children's space, rather than the maximum allotted size for the parent, which is probably not desired.
HINT_INITIAL_SIZE, HINT_MAXIMINUM_SIZE, HINT_MINIMUM_SIZE, HINT_FIXED_SIZE
If you know certain sizing restrictions for window or interaction objects, you can set them with the following four hints. Each takes a parameter that details the appropriate height and width in points. The parameters are described for the hints.
HINT_INITIAL_SIZE
CompSizeHintArgs
, a structure that defines a suggested width, height, and the number of children the object has.
HINT_FIXED_SIZE
HINT_INITIAL_SIZE
, of type
CompSizeHintArgs
.
HINT_MAXIMUM_SIZE
HINT_INITIAL_SIZE
, of type
CompSizeHintArgs
.
HINT_MINIMUM_SIZE
HINT_INITIAL_SIZE
, of type
CompSizeHintArgs
.The following examples show different ways to set the initial size of an object. The third argument of the hint is the number of children in a particular line of a composite, when the composite is set up to wrap its children.
This example sets the initial size of the composite (probably a GenPrimary) to be half the screen's height and half the screen's width.
HINT_INITIAL_SIZE = {
SST_PCT_OF_FIELD_WIDTH | PCT_50,
SST_PCT_OF_FIELD_HEIGHT | PCT_50,
0 };
This example sets the size of the composite to be 100 pixels high and 200 pixels wide.
HINT_FIXED_SIZE = {
SST_PIXELS | 200,
SST_PIXELS | 100,
0 };
This example sets the composite's minimum size to be 10 average characters wide and 20 percent of the screen height tall.
HINT_MINIMUM_SIZE = {
SST_AVG_CHAR_WIDTHS | 10,
SST_PCT_OF_FIELD_HEIGHT | PCT_20,
0 };
HINT_DRAW_IN_BOX
Often it is useful to outline a composite, especially if it is used for organizational purposes within another composite. You can use the hint
HINT_DRAW_IN_BOX
to have the UI automatically draw a box at the object's bounds as shown below.
Nearly all generic objects will have visual monikers (usually text labels) that get drawn somewhere in or near the object. The moniker helps the user distinguish between different objects; for example, each trigger should have a text (or graphical) moniker giving some indication of what happens when the trigger is pressed.
HINT_PLACE_MONIKER_ABOVE, HINT_PLACE_MONIKER_BELOW, HINT_PLACE_MONIKER_TO_LEFT, HINT_PLACE_MONIKER_TO_RIGHT, HINT_DO_NOT_USE_MONIKER, HINT_CENTER_MONIKER, HINT_PLACE_MONIKER_ALONG_LARGER_DIMENSION, HINT_ALIGN_LEFT_MONIKER_EDGE_WITH_CHILD
Monikers are extremely useful and dynamic--see the GenClass chapter, for full information on creating, manipulating, and using visual monikers. Monikers may be created or changed at run-time (often causing geometry updates), and all generic objects may be given monikers.
If you place a composite object's moniker to one side of its children, the geometry manager will ensure extra space in the composite gets allotted for the moniker. You can hint that the moniker should be placed above, to the right of, to the left of, or below the children. You can also hint that the moniker should not be used.
Most specific UIs will put the moniker to the left of the object's children by default. You can also center the moniker on the composite's children with
HINT_CENTER_MONIKER
.
You can also have the UI place the moniker along the object's larger dimension--to the left if the screen is wider than it is tall, or above if the screen is taller than it is wide. To do this, set the hint
HINT_PLACE_MONIKER_ALONG_LARGER_DIMENSION
.
If a moniker is placed above a group of children, HINT_ALIGN_LEFT_MONIKER_EDGE_WITH_CHILD ensures that left moniker edge coincides with the left edge of the first child below that moniker. This is usually the default behavior anyway, but different specific UIs may have different default behavior.
HINT_CENTER_CHILDREN_ON_MONIKERS, HINT_LEFT_JUSTIFY_MONIKERS
When you have several composites within a single composite, you can center the composites based on the position and size of the monikers. Using the hint
HINT_CENTER_CHILDREN_ON_MONIKERS
has the effect shown in the figure above: It aligns the child composites so their monikers are right-justified at the center. Adding
HINT_LEFT_JUSTIFY_MONIKERS
has a similar effect, except the monikers are left-justified.
Note that the two hints
HINT_CENTER_CHILDREN_ON_MONIKERS
and
HINT_LEFT_JUSTIFY_MONIKERS
are valid only for composites with one or more child composites, all of which have monikers placed to their left.
HINT_NO_BORDERS_ON_MONIKERS
This hint removes borders that may appear by default around an object's moniker. For example, GenTriggers under most specific UIs have a rectangular border drawn around their moniker's borders. This hint removes these borders. It may be useful in cases where a custom border should be implemented, but in general should not be used to override the specific UI, as this may confuse the user.
HINT_CUSTOM_CHILD_SPACING, HINT_CUSTOM_CHILD_SPACING_IF_LIMITED_SPACE, HINT_MINIMIZE_CHILD_SPACING
Normally, spacing of children within a composite is left entirely up to the specific UI. You can customize spacing, however, by using the hint
HINT_CUSTOM_CHILD_SPACING
. This hint takes a single argument of type
SpecSizeSpec
, described below.
The
SpecSizeSpec
structure defines both the spacing between children and how the spacing is determined. It exists as a record with two fields: The first field is a constant of type
SpecSizeTypes
, used to interpret the second field. The second field is data based on the type specified in the first field.
The different types allowable in the first field are
xx
, where the
xx
represents any multiple of five between zero and 100 inclusive. You can get better accuracy by using your own value if desired, however.Both fields of the record are defined by using the bitwise-or operator. If you had a composite that wanted to line all its children up exactly next to each other, for example, you would specify the hint as follows:
@object GenInteractionClass @MyComp = {
GI_comp = @child1, @child2, @child3;
HINT_CUSTOM_CHILD_SPACING = SST_PIXELS | 0;
}
HINT_CUSTOM_CHILD_SPACING_IF_LIMITED_SPACE
also takes a
SpecSizeSpec
to suggest a custom amount of spacing, but only implements this custom spacing if the specific UI determines that the children are already too tightly arranged. This hint may or may not be helpful, as the specific UI often allocates a minimum amount of spacing independent of this hint.
HINT_MINIMIZE_CHILD_SPACING ensures that child spacing is kept to an absolute minimum, even if this means that object's edges will touch (in color systems) or even overlap (in black and white systems).
HINT_ALLOW_CHILDREN_TO_WRAP, HINT_WRAP_AFTER_CHILD_COUNT, HINT_DONT_ALLOW_CHILDREN_TO_WRAP, HINT_WRAP_AFTER_CHILD_COUNT_IF_VERTICAL_SCREEN
When a composite grows to fit its children and also must remain small enough to fit within its generic parent, it may wrap the children. This typically happens as a result of the user resizing a window smaller so the children of the composite no longer fit the window's width. Wrapping can occur in both the horizontal and the vertical, depending on the orientation of the composite object.
To allow a composite to wrap its children when necessary, apply the hint
HINT_ALLOW_CHILDREN_TO_WRAP
to the composite. If you want the children not to wrap, apply
HINT_DONT_ALLOW_CHILDREN_TO_WRAP
. An example of wrapping children appears below.
When
HINT_WRAP_AFTER_CHILD_COUNT
is applied and children are allowed to wrap, the composite will cause its children to wrap after a certain number are displayed. This hint takes a single integer as a parameter. For example, if you wanted three children on every line in the composite no matter how many children there were total, you would specify the composite as follows:
@object GenInteractionClass @MyComp = {
GI_comp = @child1, @child2, @child3, @child4;
HINT_ALLOW_CHILDREN_TO_WRAP;
HINT_WRAP_AFTER_CHILD_COUNT = 3;
}
The configuration shown above is demonstrated in the figure below.
A variation,
HINT_WRAP_AFTER_CHILD_COUNT_IF_VERTICAL_SCREEN
, allows you to allow child wrapping based on whether or not the screen is "vertical." If the screen is taller than it is wide, this hint will have an effect like
HINT_WRAP_AFTER_CHILD_COUNT
; if not, the hint will have no effect.
As we have seen, generic objects can be arranged and distributed in several ways. You may also place generic objects within certain areas of your user interface that are not explicitly defined. For example, in many dialog boxes, a "reply bar" is typically present where reply triggers such as "OK," "Cancel," or "Apply" are located. You may specify objects to generically place themselves within such a reply bar, even though you may not know the exact location of that reply bar as the specific UI creates it.
HINT_MAKE_REPLY_BAR, HINT_SEEK_REPLY_BAR
One special feature that many dialog boxes have is a reply bar . Typically, any dialog box that allows the user to set a number of options before applying them will have a reply bar. A reply bar usually has triggers in it for "Apply," "Cancel," and perhaps other functions (such as "Reset").
Note that many special dialog box types can have their reply bars built automatically according to the specific UI. See the Menus and Dialog Boxes chapter for full information on reply bars. If you want to create your own, however, you can with the hints in this section.
Although you have to declare each of the triggers that will appear in the reply bar, you can use
HINT_MAKE_REPLY_BAR
to set up the geometry appropriate for the specific UI. For example, Creating a Reply Bar
gives the code that will create a reply bar.
Code Display 12-4 Creating a Reply Bar
/* This reply bar has three triggers, Apply, Reset, and Cancel. * The appropriate geometry is not determined until run-time. */
@object GenInteractionClass MyReplyBar = {
GI_comp = @ApplyTrigger, @ResetTrigger, @CancelTrigger;
HINT_MAKE_REPLY_BAR;
}
@object GenTriggerClass ApplyTrigger = {
GI_visMoniker = "Apply"; }
@object GenTriggerClass ResetTrigger = {
GI_visMoniker = "Reset"; }
@object GenTriggerClass CancelTrigger = {
GI_visMoniker = "Cancel"; }
HINT_SEEK_REPLY_BAR instructs the generic object (usually a GenTrigger) to seek placement in the dialog box's reply bar. The specific UI will try to place the trigger in the reply bar of the first dialog box GenInteraction it finds that is not GIT_ORGANIZATIONAL.
HINT_SEEK_MENU_BAR, HINT_AVOID_MENU_BAR
Usually, it is left up to the specific UI whether it places any given object within a menu bar. You can suggest that objects be placed within the window's menu bar by placing HINT_SEEK_MENU_BAR on that object. Similarly, you can place HINT_AVOID_MENU_BAR on an object to suggest that it not be placed within the window's menu bar.
HINT_SEEK_X_SCROLLER_AREA, HINT_SEEK_Y_SCROLLER_AREA, HINT_SEEK_LEFT_OF_VIEW, HINT_SEEK_TOP_OF_VIEW, HINT_SEEK_RIGHT_OF_VIEW, HINT_SEEK_BOTTOM_OF_VIEW
These hints affect the placement of generic objects within GenViews. The objects must be children of a GenView for the hints to take effect.
HINT_SEEK_X_SCROLLER_AREA and HINT_SEEK_Y_SCROLLER_AREA suggest that a generic object be placed alongside the scrollbar area--either the horizontal scrollbar or the vertical scrollbar, respectively--of the GenView object.
HINT_SEEK_LEFT_OF_VIEW , HINT_SEEK_TOP_OF_VIEW, HINT_SEEK_RIGHT_OF_VIEW and HINT_SEEK_BOTTOM_OF_VIEW suggest that the generic object be placed alongside the respective side of the GenView.
HINT_SEEK_TITLE_BAR_LEFT, HINT_SEEK_TITLE_BAR_RIGHT
These hints suggest the placement of a generic object within a window's title bar. These hints are usually used on GenTriggers or GenInteractions; the objects involved should fit within the title bar area (i.e., be equivalent to tool bar icons). For each window with a title bar, only one object may have each of these hints, and the object must be a direct child of the windowed object.
HINT_POPS_UP_TO_RIGHT, HINT_POPS_UP_BELOW
A generic object that appears as a window, such as an independently-displayable GenInteraction or a GenPrimary, has special needs for positioning and sizing itself, especially when appearing initially. Specific user interfaces may differ in how windows appear on the screen. In Motif, for instance, windows initially appear in one of several staggered positions. Primary and display objects extend by default to the right edge of the screen and to the top edge of the icon area at the bottom of the screen. Other windows are usually only as large as required by their children.
The
SpecSizeWinPair
structure is often used when specifying window sizes and positions. There are several hints which signal that a window should be positioned or sized depending on the position or size of another window, the size of the screen, or other conditions. The
SpecSizeWinSpec
structure allows you to specify an offset from another window, either by a number of points (remember that there are 72 points per inch), or by means of a ratio.
typedef struct {
SpecWinSizeSpec SWSP_x;
SpecWinSizeSpec SWSP_y;
} SpecWinSizePair;
typedef WordFlags SpecWinSizeSpec; #define SWSS_RATIO 0x8000 #define SWSS_SIGN 0x4000 #define SWSS_MANTISSA 0x3c00 #define SWSS_FRACTION 0x03ff
The
SpecSizeWinPair
structure allows you to set up separate parameters for the
x
and
y
coordinates. For each coordinate, use the SWSS_RATIO flag to signal whether you are giving coordinates by means of a ratio instead of a constant. If you are using a ratio, use the SWSS_FRACTION, SWSS_MANTISSA, and SWSS_SIGN fields to specify the value of the ratio or use one of the following pre-defined constants to specify a ratio between zero and one:
#define PCT_0 0x000 #define PCT_5 0x033 #define PCT_10 0x066 #define PCT_15 0x099 #define PCT_20 0x0cc #define PCT_25 0x100 #define PCT_30 0x133 #define PCT_35 0x166 #define PCT_40 0x199 #define PCT_45 0x1cc #define PCT_50 0x200 #define PCT_55 0x233 #define PCT_60 0x266 #define PCT_65 0x299 #define PCT_70 0x2cc #define PCT_75 0x300 #define PCT_80 0x333 #define PCT_85 0x366 #define PCT_90 0x399 #define PCT_95 0x3cc #define PCT_100 0x3ff
To specify a constant offset, just use that offset, not setting the SWSS_RATIO flag. Not all windows will use the
SpecWinSizePair
structure.
HINT_POSITION_WINDOW_AT_RATIO_OF_PARENT, HINT_POSITION_WINDOW_AT_MOUSE, HINT_STAGGER_WINDOW, HINT_CENTER_WINDOW, HINT_TILE_WINDOW, HINT_WINDOW_NO_CONSTRAINTS
GenClass
has a number of hints used by the window classes to determine where the window appears initially and how the window is allowed to move about the screen. Specific UIs can override these hints when necessary or when they conflict with the UI's specifications. These hints are listed below.
HINT_POSITION_WINDOW_AT_RATIO_OF_PARENT
SpecWinSizePair
structure. This structure consists of two fields, the X position and the Y position of the new window's origin. Predetermined fraction values are names PCT_
xx
, where
xx
is a multiple of five between zero and 100 inclusive. For example, to have the window object's origin start out in the center of its parent, specify the hint as follows:HINT_POSITION_WINDOW_AT_RATIO_OF_PARENT = {
SWSS_RATIO | PCT_25, SWSS_RATIO | PCT_60
};
HINT_POSITION_WINDOW_AT_MOUSE
HINT_STAGGER_WINDOW
HINT_CENTER_WINDOWHINT_EXTEND_WINDOW_TO_BOTTOM_RIGHT, HINT_EXTEND_WINDOW_NEAR_BOTTOM_RIGHT, HINT_SIZE_WINDOW_AS_DESIRED, HINT_SIZE_WINDOW_AS_RATIO_OF_PARENT, HINT_SIZE_WINDOW_AS_RATIO_OF_FIELD, HINT_USE_INITIAL_BOUNDS_WHEN_RESTORED
GenClass
has a number of hints used by the window classes to determine the size of the window object initially and how the window is allowed to be resized on the screen. Specific UIs can override these hints when necessary or when they conflict with the UI's specifications. These hints are listed below.
HINT_EXTEND_WINDOW_TO_BOTTOM_RIGHT
HINT_EXTEND_WINDOW_NEAR_BOTTOM_RIGHT
HINT_SIZE_WINDOW_AS_DESIRED
HINT_SIZE_WINDOW_AS_RATIO_OF_PARENT
SpecWinSizePair
, described under
HINT_POSITION_WINDOW_AT_RATIO_OF_PARENT
. Instead of coordinates, however, the ratios in the structure are width and height.
HINT_SIZE_WINDOW_AS_RATIO_OF_FIELD
SpecWinSizePair
parameter indicating the ratio. See above.
HINT_KEEP_INITIALLY_ONSCREEN, HINT_DONT_KEEP_INITIALLY_ONSCREEN, HINT_KEEP_PARTIALLY_ONSCREEN, HINT_DONT_KEEP_PARTIALLY_ONSCREEN, HINT_KEEP_ENTIRELY_ONSCREEN, HINT_KEEP_ENTIRELY_ONSCREEN_WITH_MARGIN, HINT_NOT_MOVABLE
HINT_KEEP_INITIALLY_ONSCREEN
HINT_DONT_KEEP_INITIALLY_ONSCREEN
HINT_KEEP_PARTIALLY_ONSCREEN
HINT_DONT_KEEP_PARTIALLY_ONSCREEN
HINT_KEEP_ENTIRELY_ONSCREEN
HINT_KEEP_ENTIRELY_ONSCREEN_WITH_MARGINHINT_WINDOW_NO_TITLE_BAR, HINT_WINDOW_NO_SYS_MENU, HINT_WINDOW_MINIMIZE_TITLE_BAR, HINT_WINDOW_ALWAYS_DRAW_WITH_FOCUS
HINT_WINDOW_NO_TITLE_BAR instructs the specific UI to remove the title bar from a windowed object (dialog box, GenPrimary or GenDisplay). Use this hint with extreme prejudice as most of a window's functionality will not be accessible without a title bar.
HINT_WINDOW_NO_SYS_MENU instructs the specific UI to remove the system menu (or close button) from a windowed object. Again, do not use this hint unless necessary, as it overrides important features of windowed objects.
HINT_WINDOW_MINIMIZE_TITLE_BAR instructs the specific UI to minimize the area that the window's title bar occupies, if possible. (This hint is designed for use in smaller PDA-style devices.) Note that this hint usually takes away any system menus that may normally be included with the title bar. As a result, make sure that you provide another means to dismiss the window. Also note that if a window containing this hint is disabled, the window will be dismissed by the system.
HINT_WINDOW_ALWAYS_DRAW_WITH_FOCUS instructs the specific UI to draw the window as if it always contains the focus, including "high-lighting" the window's title bar, if possible. Only use this hint if it is absolutely necessary because it may confuse the user and it violates the predominant focus paradigm.