The visible classes--
VisClass
,
VisCompClass
,
VisContentClass
, and
VisTextClass
--can be extremely useful to application developers. They provide a flexibility of display and use that is unavailable with the generic UI objects. Among other features, visible objects provide the hooks for and basic functionality of custom drawing, custom input handling, and custom geometry management.
VisClass
is the parent class of all the visible classes and all visible UI objects.
VisClass
objects, by themselves, do nothing;
VisClass
must be subclassed and the objects must be placed in a visible object tree as children of a
VisCompClass
object. Together,
VisClass
and
VisCompClass
provide a large amount of the functionality required for creating a hierarchy of non-overlapping objects.
Many applications will use both
VisClass
and
VisCompClass
as well as
VisContentClass
. Before reading this chapter, however, you should be familiar with the concepts of the generic UI and with basic GEOS applications. You should have created a simple application to get familiar with the GEOS system and Goc, and you should be relatively familiar with the GenView.
You should also become familiar with both
VisContentClass
and
VisCompClass
; both of these classes and their relationship to
VisClass
1 Introduction to VisClass
2 The Visible Class Tree
3 VisClass Instance Data
3.1 VI_bounds
3.2 VI_typeFlags
3.3 VI_attrs
3.4 VI_optFlags
3.5 VI_geoAttrs
3.6 VI_specAttrs
3.7 VI_link
4 Using VisClass
4.1 Basic VisClass Rules
4.2 Drawing to the Screen
4.3 Positioning Visible Objects
4.4 Handling Input
5 Working with Visible Object Trees
5.1 Creating and Destroying
5.2 Adding and Removing
5.3 Getting Visible Tree Information
5.4 Sending Messages Through the Tree
5.5 Visible Object Window Operations
6 Visible Layers and 32-Bit Graphics
6.1 Using Visible Document Layers
6.2 Using 16-Bit Drawing Commands
6.3 The 16-Bit Limit on Visual Bounds
6.4 Handling MSG_VIS_DRAW
6.5 Managing 32-Bit Geometry
6.6 Handling Mouse Events
6.7 Setting Up the Objects
7 VisClass Error Checking
8 Creating Specific UIs
9 Basic Summary
VisClass
is one of the three visible classes you'll have to have a working knowledge of in order to use visible objects. Both of the others,
VisCompClass
and
VisContentClass
, are its subclasses, and both are important in visible object trees. However,
VisClass
provides the heart of the visible world.
VisClass
objects do nothing useful by themselves. When you subclass
VisClass
and add your own methods, however, the real power of the visible classes can be used without the programmer having to worry about the nuts and bolts of most UI issues. These classes inherently provide the following features:
MSG_VIS_RECALC_SIZE
and
MSG_VIS_POSITION_BRANCH
in Geometry Management
.
VisClass
objects can not have children, but they can be children of
VisCompClass
and
VisContentClass
objects. All of these classes support extensive tree operations including passing messages up the tree, passing messages down the tree, adding branches, removing branches, and moving branches. See Working with Visible Object Trees
.
Keyboard Event Handling
A visible object can grab the keyboard input stream and receive keyboard events as they occur. Typically, certain keystrokes will be intercepted by the specific UI even if a visible object has the keyboard grab; this ensures the object won't usurp functions expected by the user from his specific UI. (The object can, however, override keystroke interception, though this is strongly discouraged.) See the Input chapter.
VisClass
objects have an inherent knowledge of the input hierarchies. Many visible objects may need to interact with the Focus and Target input hierarchies especially, and they can also interact with the Model hierarchy as well. See the Input chapter.
Use of VisMonikers
Typically, visible objects will draw themselves in their entirety and will not need visual monikers. Monikers are typically labels attached to objects that get displayed either on or near the object. Visual monikers are most frequently used with generic UI objects, but they can be set up and used with visible objects as well. See Using Visual Monikers
.
VisClass
is a subclass of
MetaClass
Many programmers new to object-oriented programming may think that visible objects are used only in certain circumstances. On the contrary, visible objects may be used for nearly any purpose and to provide nearly any application-specific graphical or user interface functions. When used properly, visible objects can relieve you of hours of writing specialized code.
Programmers new to OOP may need to practice with several small applications in order to gain experience using visible objects. You can also study the sample applications, many of which use visible objects extensively.
Visible objects are most useful when you have well-defined items that must appear on the screen or interact with the user. Pieces in a board game provide a good example: Each piece has its own visual representation, and each piece has a special set of behaviors that depend on user actions and game context. Therefore, it makes sense to have each piece be an object of
VisClass
.
Another, less immediately obvious, example might be a program that represents maps on the screen. The map itself could be stored as a visible composite object (
VisCompClass
), and each of the major subdivisions on the map could be a visible object. For example, in a map of the United States, the country would be a VisComp object, and each state could be a Vis object. Taken one step further, each state could be a composite object, and each county in the state a visible child of the state. Another step turns the counties into composite objects and each town a visible object. This arrangement lends itself to a tree structure, which is how visible objects are stored.
Another example is a spreadsheet application. The spreadsheet itself could be one composite object containing a number of row objects. Each row object is a composite that holds a number of cell objects. Each cell is a visible object with the functions of the cell built into it. The row and spreadsheet composites can use the geometry manager to arrange the cells properly, thereby making the programmer free of ever having to worry where the cells are in the document. The visible object tree will automatically pass input events to the cell under the mouse pointer. Entire rows can be created, destroyed, drawn, erased, or moved with a few simple commands by the programmer.
As stated earlier, the visible class tree consists of four classes.
VisClass
VisCompClass
VisClass
, this class has the added ability to have and arrange children in the visible tree. It has sophisticated geometry management functions built in and can be used as an organizational object.
VisContentClass
VisCompClass
, this class is used only as the content of a GenView. The VisContent has default handlers for many messages sent out by the view, and it interacts with the view window to display the visible object tree. Every visible object tree, to be displayed in a GenView, must have a VisContent as its root object.
VisTextClass
GenTextClass
. It provides a nearly full-featured word processing object that can be put in the visible tree.The first three of these classes are used extensively by many applications.
VisClass
has seven different instance data fields as shown in VisClass Instance Data
. Each of these fields is discussed in detail in the following sections, and each may be set or reset during execution by sending the visible object certain messages.
Several of the instance fields will never be used by the application programmer. Most likely, you will work directly with the
VI_bounds
field and perhaps the
VI_attrs
or
VI_geoAttrs
fields. It's unlikely you will need to use the others unless you're doing something quite unusual.
Code Display 15-1 VisClass Instance Data
/* This is the definition of the VisClass instance data fields with some comments * as to their use. */
/* VI_bounds * VI_bounds is a Rectangle structure defining the outermost boundaries of * the visible object. */
@instance Rectangle VI_bounds = {0, 0, 0, 0};
/* VI_typeFlags * VI_typeFlags is a record containing eight flags that determine the * type of the visible object. None are set by default. */
@instance VisTypeFlags VI_typeFlags = 0; /* Possible flags: * VTF_IS_COMPOSITE VTF_IS_WINDOW * VTF_IS_PORTAL VTF_IS_WIN_GROUP * VTF_IS_CONTENT VTF_IS_INPUT_NODE * VTF_IS_GEN VTF_CHILDREN_OUTSIDE_PORTAL_WIN */
/* VI_attrs * VI_attrs is a record that contains eight attribute flags for the * object. Those set by default are shown. */
@instance VisAttrs VI_attrs = (VA_MANAGED | VA_DRAWABLE | VA_DETECTABLE | VA_FULLY_ENABLED); /* Possible flags: * VA_VISIBLE VA_FULLY_ENABLED * VA_MANAGED VA_DRAWABLE * VA_DETECTABLE VA_BRANCH_NOT_MINIMIZABLE * VA_OLD_BOUNDS_SAVED VA_REALIZED */
/* VI_optFlags * VI_optFlags is a record containing eight window update flags. * The flags set by default are shown. */
@instance VisOptFlags VI_optFlags = (VOF_GEOMETRY_INVALID | VOF_GEO_UPDATE_PATH | VOF_WINDOW_INVALID | VOF_WINDOW_UPDATE_PATH | VOF_IMAGE_INVALID | VOF_IMAGE_UPDATE_PATH); /* Possible flags: * VOF_GEOMETRY_INVALID VOF_GEO_UPDATE_PATH * VOF_IMAGE_INVALID VOF_IMAGE_UPDATE_PATH * VOF_WINDOW_INVALID VOF_WINDOW_UPDATE_PATH * VOF_UPDATE_PENDING VOF_EC_UPDATING */
/* VI_geoAttrs * VI_geoAttrs is a record of eight geometry management flags. */
@instance VisGeoAttrs VI_geoAttrs = 0; /* Possible flags: * VGA_GEOMETRY_CALCULATED VGA_NO_SIZE_HINTS * VGA_NOTIFY_GEOMETRY_VALID VGA_DONT_CENTER * VGA_USE_VIS_SET_POSITION VGA_USE_VIS_CENTER * VGA_ALWAYS_RECALC_SIZE VGA_ONLY_RECALC_SIZE_WHEN_INVALID
/* VI_specAttrs * VI_specAttrs is a record containing eight flags used when the visible * object is part of a specific UI library. This field is rarely if ever * used by applications. */
@instance SpecAttrs VI_specAttrs = 0; /* Possible flags: * SA_ATTACHED SA_REALIZABLE * SA_BRANCH_MINIMIZED SA_USES_DUAL_BUILD * SA_CUSTOM_VIS_PARENT SA_SIMPLE_GEN_OBJ * SA_CUSTOM_VIS_PARENT_FOR_CHILD * SA_TREE_BUILT_BUT_NOT_REALIZED */
/* VI_link * VI_link contains an object pointer to the visible object's next sibling * in the tree. Note that VisClass has no corresponding @composite field; * if the object is to have children, it must be of class VisCompClass.
@instance @link VI_link;
The
VI_bounds
field is a
Rectangle
structure containing four values: The left, top, right, and bottom outer bounds of the object. The bounds of a visible object describe the object to the rest of the world: the input manager and UI use them to determine when the mouse pointer is over the object, and the object's visible parent (if any) uses them to figure out the total geometry of all its children.
The
VI_bounds
field is very important to nearly all visible objects. In fact, Positioning Visible Objects
is devoted to this field and how it is used. For full information on visible bounds, see that section.
VI_typeFlags, MSG_VIS_SET_TYPE_FLAGS, MSG_VIS_GET_TYPE_FLAGS
The
VI_typeFlags
field is a bitfield record containing eight flags. These flags determine the type of the visible object and are used primarily by the UI and the windowing system. When used at all, these flags are typically set in the object's definition or when the object is first created, and they are rarely changed dynamically by an application. The eight flags in this record are listed below. The record is of type
VisTypeFlags
.
VisCompClass
rather than
VisClass
. This flag indicates the object may have children (normal
VisClass
objects can not have children). Because this is not the only difference between these classes, changing this flag can have unpredictable results.
VisCompClass
and not
VisClass
. If this flag is set, the UI will assume that the
VI_bounds
field of the object represents the current size of the window. Objects with the VTF_IS_WINDOW flag set are skipped by the normal input and output messages such as
MSG_VIS_DRAW
and
MSG_META_START_SELECT
; these messages will be passed directly to the object's appropriate child. VTF_IS_WINDOW and VTF_IS_PORTAL are mutually exclusive.
VisContentClass
(not for
VisClass
or
VisCompClass
). Note that if this is set, both VTF_IS_WINDOW and VTF_IS_WIN_GROUP must also be set.
MSG_VIS_VUP_ALTER_INPUT_FLOW
is sent directly to objects with this bit set unless there is a need for them to actually use the VUP mechanism, as is the case with mouse grabs in a 32-bit content. Similarly,
MSG_META_MUP_ALTER_FTVMC_EXCL
,
MSG_VIS_FUP_QUERY_FOCUS_EXCL
, and
MSG_VIS_VUP_QUERY_FOCUS_EXCL
are sent to the first visible object up the tree that either is a window group or has this bit set.
MSG_SPEC
. The only objects that will ever have this flag set are those in Specific UI libraries.
Although the
VI_typeFlags
record will rarely be changed at run-time, you can set new values by sending
MSG_VIS_SET_TYPE_FLAGS
to the visible object while it is realized. To retrieve the current type flags, send the object a
MSG_VIS_GET_TYPE_FLAGS
.
void MSG_VIS_SET_TYPE_FLAGS(
VisTypeFlags flagsToSet,
VisTypeFlags flagsToClear);
This message causes the object to set its
VI_typeFlags
field to the values passed. The
flagsToSet
parameter will be OR-ed with
VI_typeFlags
, and the
flagsToClear
parameter will be logically inverted and then AND-ed with the field. The clear operation will occur after the set. Therefore a flag set in both parameters will be cleared by this message.
Source: Unrestricted.
Destination: Any visible object; however, the object must not be realized when it receives the object.
Parameters:
flagsToSet
A record of
VisTypeFlags
indicating which flags are to be set for the object.
flagsToClear
VisTypeFlags
indicating which flags are to be cleared for the object (a flag set in
flagsToClear
will be cleared in
VI_typeFlags
).Return: Nothing.
Interception: Unlikely.
VisTypeFlags MSG_VIS_GET_TYPE_FLAGS();
This message returns a visible object's current
VI_typeFlags
field.
Source: Unrestricted.
Destination: Any visible object.
Parameters: None.
Return: A byte of
VisTypeFlags
representing the object's current
VI_typeFlags
field.
Interception: Unlikely.
VI_attrs, MSG_VIS_GET_ATTRS, MSG_VIS_SET_ATTRS
The
VI_attrs
field is a record of eight flags (
VisAttrs
)that determine the general visible attributes of the object. These attributes may be changed on the fly and often are. Applications that don't involve visible tree operations (adding, removing, or moving branches) probably will not change these attributes dynamically.
To set the flags after the object has been instantiated, send it a
MSG_VIS_SET_ATTRS
with the appropriate flags to be set. To retrieve the
VI_attrs
record, send the object a
MSG_VIS_GET_ATTRS
. The VA_REALIZED flag may not be changed with
MSG_VIS_SET_ATTRS
.
The eight flags of the
VisAttrs
record are listed below:
VI_typeFlags
) and is ignored for other objects. If set, it indicates that the visible branch headed by this object can be made visible as soon as it is linked visibly to another visible branch. For example, a window group object may have this bit set and not be on the screen if its parent window group is not set VA_VISIBLE; as soon as the parent window group becomes VA_VISIBLE, though, the entire branch will become visible.
VI_bounds
field will automatically be marked invalid.
MSG_VIS_SET_ATTRS
resets the flag, the object will retain the mouse grab until it is released or preempted normally.
VI_bounds
field changes. The old bounds are stored in a TEMP_VIS_OLD_BOUNDS vardata field.
MSG_VIS_SET_ATTRS
; it may only be changed by
MSG_VIS_OPEN
(which sets the flag) and
MSG_VIS_CLOSE
(which resets it).void MSG_VIS_SET_ATTRS(
VisAttrs attrsToSet,
VisAttrs attrsToClear,
VisUpdateMode updateMode);
This message sets the object's
VI_attrs
field to the values passed. The
attrsToSet
parameter will be OR-ed with
VI_attrs
, and the
attrsToClear
parameter will be logically inverted and then AND-ed with the field. The clear operation will occur after the set, and therefore a flag set in both parameters will be cleared. The
updateMode
parameter indicates when the visual update of the object should occur after the new attributes have been set.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
attrsToSet
A record of
VisAttrs
indicating which flags are to be set for the object.
attrsToClear
VisAttrs
indicating which flags are to be cleared for the object (a flag set in
attrsToClear
will be cleared in
VI_attrs
).
updateMode
VisUpdateMode
indicating when the object should be visually updated on the screen.Return: Nothing.
Interception: Unlikely.
Warnings: Not all flags in the
VI_attrs
record may be set with this message.
VisAttrs MSG_VIS_GET_ATTRS();
This message returns a visible object's current
VI_attrs
field.
Source: Unrestricted.
Destination: Any visible object.
Parameters: None.
Return: A byte of type
VisAttrs
representing the current flags set in the object's
VI_attrs
field.
Interception: Unlikely.
VI_optFlags, MSG_VIS_GET_OPT_FLAGS
The
VI_optFlags
field is a
VisOptFlags
record containing eight flags. These flags are set and used by the geometry manager to mark which objects need to be updated and how. The flags can not be set individually by applications; however, they can be retrieved with the message
MSG_VIS_GET_OPT_FLAGS
. It is unlikely that your code will ever access these flags directly. The eight flags in this field are listed below.
MSG_VIS_MARK_INVALID
). This is used primarily when an object knows that its bounds must be recalculated or re-verified and that any change must be reflected in its parent window. This flag will be reset when a geometry update resolves the object's bounds. Typically, this will occur with a window update message such as
MSG_VIS_UPDATE_WIN_GROUP
.
MSG_VIS_MARK_INVALID
, marks a trail of objects that all must have their geometry updated.
MSG_VIS_MARK_INVALID
. The image redraw will occur the next time one of the window update messages is used on the object's visual branch. This flag will be reset when a visual update redraws the object. Typically, this will occur with
MSG_VIS_UPDATE_WIN_GROUP
or another window update message.
MSG_VIS_MARK_INVALID
, marks a trail of objects that must have their images updated.
MSG_VIS_OPEN
or
MSG_VIS_CLOSE
. It is set by
MSG_VIS_MARK_INVALID
. This flag will be reset when a visual update occurs on the window group. Typically, this will occur with a window update message such as
MSG_VIS_VUP_UPDATE_WIN_GROUP
. (This message should be called whenever an object is added to a visible tree; it ensures the object will be properly opened.)
MSG_VIS_MARK_INVALID
, marks a trail of window objects that all must have their windows and open/closed state updated.
MSG_VIS_UPDATE_WIN_GROUP
in its event queue.
VisClass
error-checking code only. It indicates that a visible branch is currently being updated; the system checks it to make sure nested updates do not occur.VisOptFlags MSG_VIS_GET_OPT_FLAGS();
This message returns the current
VI_optFlags
field of the object.
Source: Unrestricted.
Destination: Any visible object.
Parameters: None.
Return: A byte record of
VisOptFlags
reflecting the current settings in the object's
VI_optFlags
field.
Interception: Unlikely.
See Also:
MSG_VIS_MARK_INVALID.
VI_geoAttrs, MSG_VIS_SET_GEO_ATTRS, MSG_VIS_GET_GEO_ATTRS
The
VI_geoAttrs
field is a
VisGeoAttrs
record of eight flags that determine the state of the object's geometry. They can be set and reset during execution to dynamically change the geometry behavior of the object. None of the flags is set by default. To set the flags, send the object a
MSG_VIS_SET_GEO_ATTRS
. The flags can be retrieved with a
MSG_VIS_GET_GEO_ATTRS
. The eight flags in this record are listed below.
MSG_VIS_RESET_TO_INITIAL_SIZE
.
HINT_INITIAL_SIZE
or
HINT_FIXED_SIZE
).
MSG_VIS_NOTIFY_GEOMETRY_VALID
. This flag may be used by visual objects for calculations or other sizing once geometry is redone but before redrawing occurs.
MSG_VIS_SET_POSITION
and
MSG_VIS_POSITION_BRANCH
. This flag provides an optimization that allows static calls to the geometry manager.
VisClass
or
VisCompClass
center message to calculate the object's center. Unless an object is using some unusual centering behavior, it should have this flag set. This flag allows the geometry manager to speed up calculations for normal center behavior.void MSG_VIS_SET_GEO_ATTRS(
VisGeoAttrs attrsToSet,
VisGeoAttrs attrsToClear,
VisUpdateMode updateMode);
This message causes the object to set its
VI_geoAttrs
field to the values passed. The
attrsToSet
parameter will be OR-ed with
VI_geoAttrs
, and the
attrsToClear
parameter will be logically inverted and then AND-ed with the field. The clear operation will occur after the set, and therefore a flag set in both parameters will end up cleared. Many of the attributes in this record are used only by Specific UI libraries and should not be altered by applications.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
attrsToSet
A record of
VisGeoAttrs
indicating which flags are to be set for the object.
attrsToClear
VisGeoAttrs
indicating which flags are to be cleared for the object (a flag set in
attrsToClear
will be cleared in
VI_geoAttrs
).
updateMode
VisUpdateMode
indicating when the object should be visually updated on the screen.Return: Nothing.
Interception: Unlikely.
VisGeoAttrs MSG_VIS_GET_GEO_ATTRS();
This message returns a visible object's current
VI_geoAttrs
field.
Source: Unrestricted.
Destination: Any visible object.
Parameters: None.
Return: A record of type
VisGeoAttrs
reflecting the flags currently set in the object's
VI_geoAttrs
field.
Interception: Unlikely.
VI_specAttrs, MSG_SPEC_SET_ATTRS, MSG_SPEC_GET_ATTRS
The
VI_specAttrs
field is a record of eight flags. This field is accessed only by objects that are part of a Specific UI library. Applications will almost never access this field or use its flags. Documentation on creating specific UI libraries may be published under separate cover.
void MSG_SPEC_SET_ATTRS(
SpecAttrs attrsToSet,
SpecAttrs attrsToClear,
VisUpdateMode updateMode);
This message sets the current
VI_specAttrs
field to the values passed. A flag set in both attributes parameters will be cleared.
Source: Unrestricted.
Destination: Any visible object used as a specific UI object.
Parameters:
attrsToSet
A record of
SpecAttrs
indicating which flags are to be set in the object's
VI_specAttrs
field.
attrsToClear
VisAttrs
indicating which flags are to be cleared for the object (a flag set in
attrsToClear
will be cleared in
VI_specAttrs
).
updateMode
VisUpdateMode
indicating when the object should be visually updated on the screen.Return: Nothing.
Interception: Unlikely.
SpecAttrs MSG_SPEC_GET_ATTRS();
This message returns a visible object's current
VI_specAttrs
field. This field is used only by Specific UI libraries and is meaningful only for objects in these libraries.
Source: Unrestricted.
Destination: Any visible object that is used as a specific UI object.
Parameters: None.
Return: A byte of type
SpecAttrs
indicating which flags are set in the object's
VI_specAttrs
field.
Interception: Unlikely.
VI_link
The
VI_link
field holds the optr of the visible object's next sibling in the visible object tree. This field may not be accessed directly by applications but may be set or changed with the various visible tree messages. For full information on how to build and manipulate visible object trees, see Working with Visible Object Trees
.
As stated earlier, visible objects are nearly useless unless you subclass one of the visible classes and handle certain messages. Although there's a lot of functionality built into
VisClass
and its subclasses, they must be customized to be of any use. In addition, visible objects must be put into a visible tree and connected to a GenView or other windowed UI object to be displayed.
To use visible objects, you must subclass the Vis classes and create a visible object tree. Otherwise, the visible objects will not be able to display themselves or accept user input, the two things that make visible objects worthwhile.
Nearly all visible objects you use will at least display themselves on the screen. Some may accept mouse or keyboard input; some may move themselves around the screen, resize themselves, or implement custom geometry management functions.
For a subclass of
VisClass
to display itself on the screen, it must handle the message
MSG_VIS_DRAW
. This message is sent to all visible objects in a given window when that window is subjected to an exposure event. In addition, the object must be part of a tree of visible objects, the top node of which is connected to a GenView or other windowed object. Displaying a basic visible object is discussed below.
For a visible object to handle mouse input, it will need to handle a subset of the mouse event messages. Typically, a visible object will want to know when the mouse is clicked within the object's bounds (
MSG_META_START_SELECT
) and when the mouse button is released (
MSG_META_END_SELECT
). Other messages dealing with mouse motion or other mouse buttons may also be of interest to the object. In addition, visible objects may request and handle Ink input. Handling of these messages is discussed in Handling Input
.
Most applications using visible object trees will add objects to and remove them from the trees.
MSG_VIS_ADD_CHILD
and
MSG_VIS_REMOVE
are the two messages used most often for tree management. When an object should be freed, it can be destroyed with
MSG_VIS_DESTROY
, which will remove it from the tree and then free it.
Some applications will want to use the built-in geometry management features of GEOS. The geometry manager can automatically resize and reposition an entire visible object tree properly according to pre-set constraints. (The constraints can also be changed at run-time.) How the system manages visible object geometry is discussed in Geometry Management .
The geometry manager, though extremely useful for non-overlapping objects, may not be sufficient for all the needs of a complex application. For an object to determine its own size and position, it has to handle some of the messages sent out by the geometry manager. You can also manually set the size and position of each visible object. This is discussed in Positioning Visible Objects .
Often applications may need to change something about a visible object or the tree it's in. When this happens, the application must force a visual update by invalidating either the geometry or the image (or both) of the object and then calling
MGS_VIS_VUP_UPDATE_WIN_GROUP
. To mark any object invalid, the application must call
MSG_VIS_MARK_INVALID
.
Many visible objects will have specific functions they perform. For example, if the user presses on a menu item labeled "New Game" or something similar, the visible object may return itself to its original location (as in the TicTac sample application). To get this type of functionality, you must define new messages for your subclass of
VisClass
and have the object handle them. In the case of the TicTac game pieces, each piece handles the
MSG_PIECE_NEW_GAME
message by resetting the object's position to its original position.
Visible objects are maintained and managed in a tree structure. The tree has three basic elements: The root (topmost) node must be an object of
VisContentClass
. Any nodes in the middle of the tree, nodes that are allowed to have children, must be of
VisCompClass
. Any leaf nodes (guaranteed not to have children) may be of either
VisClass
or
VisCompClass
. (Subclasses of the above classes may also be used.)
The visible object tree is displayed normally through a GenView object. The output of the GenView must be tied directly to the top node of the visible object tree; this is why the visible tree must be headed by a VisContent--only the VisContent has the methods to handle GenView messages.
The VisContent object may or may not do things other than manage the visible tree. For example, the content may draw some background graphics to the window before the other visible objects draw themselves, or it may implement some special geometry behavior to arrange its children.
The VisContent can have children. These children can be either standard visible objects or
composite
visible objects. Composites, like the content, are allowed to have children. For efficiency, standard visible objects can not have children. Therefore, only leaf objects in the tree may be of
VisClass
.
The visible object tree may have any number of layers of composites. You should pay attention to the functions required in your application and fit the structure of the tree to the application's needs.
These restrictions, combined with the link to the generic object tree through GenView, result in an object tree structure somewhat like that shown in the figure above. Of course, the actual generic and visible tree structure will vary from application to application. Also, note that the generic and visible sections are actually two different object trees; they are not connected through a parent-child relationship anywhere.
One of the main features of visible objects is their ability to draw themselves on the screen. The visible tree does not have to detect when drawing or redrawing should be done; the UI will do this automatically through the window system and the GenView object.
MSG_VIS_OPEN, MSG_VIS_CLOSE
The visible tree will have to draw or redraw itself when a portion of its GenView window becomes newly exposed. The GenView keeps track of its window and will notify its content when any portion of the window becomes exposed. Exposure can occur from several events: The view window could be newly created; another window could have been moved, exposing the view's window; or the view window could have been scrolled.
Each of these exposure events looks exactly the same to the visible tree. When one of them occurs, the GenView will send a
MSG_META_EXPOSED
to its content object. The content (a VisContent or GenDocument if you're using a visible tree) will create a GState for the window and translate the
MSG_META_EXPOSED
into a
MSG_VIS_DRAW
. It will then send this
MSG_VIS_DRAW
to itself.
The default handler for
MSG_VIS_DRAW
in a composite is to simply pass the message on to all of the composite's children. There is no default behavior for
MSG_VIS_DRAW
in
VisClass
.
Any object (content, composite, or leaf) that wants to represent itself on the screen must handle
MSG_VIS_DRAW
. Any composite that subclasses this message must be sure to pass it on to all of its children with the following line:
@send @visChildren:: MSG_VIS_DRAW(drawFlags, gstate);
Redrawing is not initiated only by the view window becoming exposed. It can also be initiated by some portion of the visible tree changing so that it needs to be redrawn (e.g., a child is moved from one composite to another, which may have an effect on the visual representation of the composite). Typically, any change that necessitates a redrawing will automatically generate a
MSG_VIS_DRAW
to the appropriate objects. These operations, however, will require a
VisUpdateMode
to be passed along with the other parameters.
All of the above assumes that the visible object is "open" or "realized." If an object is not open, it will not appear on the screen or as part of a composite's geometry calculations. When a window is first created, the window's content is automatically opened with
MSG_VIS_OPEN
. In the case of a visible tree attached to a GenView, this means that the VisContent object will be opened along with the window. All of the VisContent's children will also be opened automatically (assuming their VOF_WINDOW_INVALID bits are set, which is true the first time a visible object comes up).
If a visible object is added to an already-opened composite, the child will automatically be opened and marked invalid. This will cause the composite's geometry and image to be updated during the next visual update. If a child is added to a composite that is not currently open, the child will not be opened.
Although it is rarely done directly, you can manually open a visible object with the message
MSG_VIS_OPEN
, and you can "close" an object (remove it from the screen and from the tree's geometry calculations) with
MSG_VIS_CLOSE
. To open or close an entire branch of the visible tree, you can send the appropriate message to the top composite object in the branch. The message will propagate down through all the visible children.
void MSG_VIS_OPEN(
WindowHandle window);
This message is part of the visual update mechanism and will be sent by the system when an object must be visually updated to appear on the screen. It will be sent to any VOF_WINDOW_INVALID objects in a branch whose VTF_IS_WIN_GROUP object has become VA_VISIBLE. Any object added into a visible tree having VOF_WINDOW_INVALID set will receive a
MSG_VIS_OPEN
at the next visual update. This message propagates down the visible tree and does
not
cross over boundaries of window groups. This message is often subclassed by objects that want to initialize some information before being drawn on the screen. If an object subclasses this message, it should be sure to call its superclass somewhere in the handler.
Source: Visual update mechanism.
Destination: Any visible object.
Parameters:
window
Handle of window in which the object is to appear, or zero if it should appear in the top window object.
Return: Nothing.
Interception: Will be intercepted by objects that want to initialize certain data or take certain actions before being drawn on the screen. Any intercepting objects must call the superclass somewhere in their handler.
void MSG_VIS_CLOSE();
This message is part of the visual update mechanism and is sent to objects that are being taken off the screen. The system will send this message to any objects in a visual branch whose VTF_IS_WIN_GROUP object is set not visible (~VA_VISIBLE). This message closes appropriate windows and propagates to all children to the bottom leaf objects of the visible branch. This message will not cross window group boundaries; if a lower VTF_IS_WIN_GROUP object is encountered during the message propagation, an error will likely occur. Therefore, lower window groups must be closed before higher window groups may be closed.
Source: Visual update mechanism.
Destination: Any visible object.
Interception: Will be intercepted by objects that want to do something as it is being taken off the screen. Any objects that intercept the message must call their superclasses in the handlers.
VisUpdateMode
is an enumerated type that determines when and how the visible tree will be visually updated when its image or geometry becomes invalid. This type has four enumerations, described below:
A
VisUpdateMode
is passed as a parameter to certain Vis and Gen messages. These messages typically have some effect on the visual representation of the objects--either on the geometry or on the image itself.
MSG_VIS_VUP_CREATE_GSTATE
For any drawing to occur, a graphic state must exist. The graphic state typically is associated with the GenView's window and is created automatically, either when the window is first realized on the screen or when an exposure event occurs.
To create a GState, the system generates a
MSG_VIS_VUP_CREATE_GSTATE
and sends it to the object that first requires a visual update. This message travels up the visible tree until it gets to a window group (an object with its VTF_IS_WINDOW flag set), and then it creates a GState associated with that window object. Sometimes a content object will subclass this message to set up its own display information before the GenView window can create the new GState. The other time in which this message may be subclassed is by a content that manages a 32-bit graphics space; the content will have to translate the gstate to the proper position in the large document before letting other objects use it.
GStateHandle MSG_VIS_VUP_CREATE_GSTATE();
This message travels up the visible object tree until it reaches either the root object or a window group object. It then creates a graphic state associated with that object; this graphic state is then used for the subsequent visual update. You may wish to subclass this message in order to alter the GState created or to set it up to take 32-bit coordinates. If you subclass it, however, be sure to call the superclass somewhere in the handler.
Source: Unrestricted--typically sent by a visible object to itself.
Destination: Any visible object--typically sent by a visible object to itself.
Parameters: None.
Return: The GStateHandle of the newly-created GState.
Interception: Unlikely--VisContent objects may intercept this message to translate the returned GState in a 32-bit graphics space. In this case, the VisContent must first call its superclass, then translate the GState appropriately before returning.
MSG_VIS_QUERY_WINDOW
Often a visible object will require the window handle of the window it's currently residing in. Some objects, for example, will want to force visual updates in real-time, and they can do this by using the current window handle, creating a special GState for it, and drawing to that GState. The visible object can either cache the window handle when the window is first opened, or it can retrieve it with
MSG_VIS_QUERY_WINDOW
.
WindowHandle MSG_VIS_QUERY_WINDOW();
This message returns the window handle of the window the object currently resides in. In many cases, this will be the window handle of a GenView window.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself to retrieve its current window handle.
Parameters: None.
Return: The window handle of the object's current window.
Interception: Unlikely.
See Also:
MSG_GEN_VIEW_GET_WINDOW.
MSG_VIS_BOUNDS_CHANGED, MSG_VIS_REDRAW_ENTIRE_OBJECT, MSG_VIS_INVALIDATE, MSG_VIS_MARK_INVALID, MSG_VIS_INVAL_TREE, MSG_VIS_ADD_RECT_TO_UPDATE_REGION
If your visible tree contains a composite that manages its own children, chances are you'll need to force a visual update after certain changes occur. For example, if you have an object that can be moved with the mouse, it will probably want to erase its image and redraw itself somewhere else after the move; since the geometry manager is not involved here, the object must force a redrawing of the affected portion of the visible tree.
There are several ways an object can force a redraw. These all take the form of messages, each of which is described below.
MSG_VIS_DRAW
MSG_VIS_VUP_UPDATE_WIN_GROUP
.
MSG_VIS_BOUNDS_CHANGED
MSG_VIS_REDRAW_ENTIRE_OBJECT
MSG_VIS_DRAW
when it receives this message. This is especially useful if an object needs to completely change its image.
MSG_VIS_INVALIDATE
MSG_META_EXPOSED
for the affected area, causing a
MSG_VIS_DRAW
to propagate down the tree to all affected objects. Note that this message must be subclassed to work with scaled windows or large documents.
MSG_VIS_INVAL_TREE
MSG_META_EXPOSED
for all affected windows.
MSG_VIS_MARK_INVALID
MSG_VIS_ADD_RECT_TO_UPDATE_REGIONvoid MSG_VIS_DRAW(
DrawFlags drawFlags,
GStateHandle gstate);
This message causes the visible object to draw itself. The default behavior of this message for composite objects is to pass the message on to all children. There is no default behavior for
VisClass
for this message.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
drawFlags
A record of type
DrawFlags
(defined below). The flags in this record describe what type of action initiated the
MSG_VIS_DRAW
.
gstate
Return: Nothing.
Interception: All visible objects that wish to draw anything to the screen must intercept this message. Composites that intercept it must be sure to send it to their children (with
@send @visChildren
).
Structures: The flags in the
DrawFlags
record are listed below:
MSG_VIS_DRAW
is a result of a
MSG_META_EXPOSED
from the window system. This is the standard and most usual form of
MSG_VIS_DRAW
.
MSG_VIS_DRAW
is a result of a
MSG_META_EXPOSED_FOR_PRINT
, the printing message. The GState passed will be a spooler GState rather than a window GState. If this flag is set, DF_EXPOSED will also be set.
DisplayClass
. For review, the types are listed below:void MSG_VIS_BOUNDS_CHANGED(@stack
word bottom,
word right,
word top,
word left);
The geometry manager sends this message when a geometry update changes an object's bounds.
Source: Unrestricted--sent by the geometry manager when a visible object's bounds have changed as the result of a geometry change.
Destination: Any visible object.
Parameters:
bottom
,
right
,
top
,
left
The four parameters correspond to the rectangle defining the object's old bounds. The parameters are passed on the stack.
Return: Nothing.
Interception: Unlikely. If the object subclasses this message, it should invalidate any part of its old bounds that it might have drawn in (the default handler invalidates the entire passed range).
void MSG_VIS_REDRAW_ENTIRE_OBJECT();
This message causes the object send itself a
MSG_VIS_DRAW
, creating and destroying a GState for itself.
Source: Unrestricted--typically sent by an object to itself because of a state change, not as part of the visual update mechanism.
Destination: Any visible object--typically sent by an object to itself.
Interception: Unlikely.
void MSG_VIS_INVALIDATE();
This message invalidates the entire region within the object's bounds. The message will cause the window system to generate a
MSG_META_EXPOSED
for the area covered by the bounds, causing a visual update to occur.
Source: Unrestricted.
Destination: Any visible object.
Interception: Must be intercepted if the object is working in a 32-bit document space. Must also be intercepted to work with scaled views.
void MSG_VIS_INVAL_TREE();
This message has the effect of
MSG_VIS_INVALIDATE
on an entire branch of the visible tree. The window system will generate
MSG_META_EXPOSED
for each affected window.
Source: Unrestricted.
Destination: Any visible object.
Interception: Unlikely.
void MSG_VIS_MARK_INVALID(
VisOptFlags flagsToSet,
VisUpdateMode updateMode);
This message allows the caller to set the recipient's
VI_optFlags
record so the object will get updated properly during the next visual update. The flags that can be set with this message are VOF_GEOMETRY_INVALID, VOF_WINDOW_INVALID, and VOF_IMAGE_INVALID. For more information on these flags, see VI_optFlags
.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
flagsToSet
A record of
VisOptFlags
indicating which type of invalidation is being caused. The flags allowed with this message are VOF_GEOMETRY_INVALID, VOF_WINDOW_INVALID, and VOF_IMAGE_INVALID.
updateMode
VisUpdateMode
indicating when the visual update caused by this message should occur.Return: Nothing.
Interception: May not be subclassed. Certain optimizations are made in the default handler, and subclassing may have unpredictable results.
void MSG_VIS_ADD_RECT_TO_UPDATE_REGION(@stack
byte unused, /* for word alignment of parameters */
VisAddRectFlags addRectFlags,
word bottom,
word right,
word top,
word left);
This message adds the passed rectangular region to the window group's list of regions that require visual update. The handler for this message will ensure that the window group object for this branch of the tree marks the region as invalid so it will be included in the next visual update. The
addRectFlags
parameter contains either of the flags listed below.
Source: Unrestricted--usually sent by an object to itself.
Destination: Any visible object--usually sent by an object to itself.
Parameters:
unused
An unused byte for alignment of parameters.
addRectFlags
VisAddRectFlags
, defined below.
rectangle coords
Return: Nothing.
Interception: Unlikely--a composite object may wish to optimize invalidation by altering the passed bounds and then passing the message on to its superclass.
Structures: The
VisAddRectFlags
are listed below:
MSG_VIS_VUP_UPDATE_WIN_GROUP, MSG_VIS_UPDATE_WIN_GROUP, MSG_VIS_UPDATE_WINDOWS_AND_IMAGE
A window group is an object that has a window in which visible objects are displayed. Typically, you will not create your own window group objects, but you may need to notify a window group when it needs to be updated visually. To be a window group, an object has to have its VTF_IS_WINDOW or VTF_IS_PORTAL flag set in its
VI_typeFlags
field.
The window group is responsible for keeping track of the regions of its coordinate space that require visual updating. When a region or object gets invalidated, the window group remembers that it is invalid and makes sure it gets updated during the next visual update.
Any object can request that a visual update occur for the entire branch managed by a window group. It can use the three messages described in this section to request or force a visual update for the window group.
Boolean MSG_VIS_VUP_UPDATE_WIN_GROUP(
VisUpdateMode updateMode);
This message travels up the visible tree from the recipient object to the first window group encountered; it will then cause that window group to go through a visible update by sending the window group object a
MSG_VIS_UPDATE_WIN_GROUP
, below.
Source: Unrestricted.
Destination: Any visible object residing in the window group that is to be updated.
Parameters:
updateMode
A
VisUpdateMode
indicating when the visual update should occur. VUM_MANUAL has the effect of a "no operation" because VUM_MANUAL does not cause visual updates.
Return: True if the update mechanism was invoked; false if it was not.
Interception: Not allowed.
Warnings: You may not subclass this message.
void MSG_VIS_UPDATE_WIN_GROUP(
VisUpdateMode updateMode);
This message may only be sent by a window group object to itself. It causes the window group to actually go through a visual update.
Source: Visible update mechanism.
Destination: The window group object that is to be updated.
Parameters:
updateMode
A
VisUpdateMode
indicating when the visual update should occur. This is the same as passed to
MSG_VIS_VUP_UPDATE_WIN_GROUP.
Return: Nothing.
Interception: Not allowed.
Warnings: You may not subclass this message.
void MSG_VIS_UPDATE_WINDOWS_AND_IMAGE(
VisUpdateImageFlags updateImageFlags);
This message is called by a window group during a visual update. It should not be sent or handled by anything other than a window group. It causes both the geometry and image of the affected branch of the visible tree to be updated, and it is used on branches which are already visually realized on the screen.
Source: Visual update mechanism.
Destination: A window group object.
Parameters:
updateImageFlags
This is a record of
VisUpdateImageFlags
that govern the visual update of the window group.
Return: Nothing.
Interception: Not allowed.
Structures: The flags of
VisUpdateImageFlags
are listed below:
Warnings: You may not subclass this message.
MSG_VIS_DRAW_MONIKER, MSG_VIS_GET_MONIKER_POS, MSG_VIS_GET_MONIKER_SIZE, MSG_VIS_FIND_MONIKER, MSG_VIS_CREATE_VIS_MONIKER
Although visual monikers are typically used with generic objects (and are, in fact, documented in the
GenClass
chapter), you can display monikers with visible objects as well. The four messages discussed in this section can be used to draw a visible moniker, get information about a moniker, or locate a particular moniker in the visible object tree.
void MSG_VIS_DRAW_MONIKER(@stack
DrawMonikerFlags monikerFlags,
ChunkHandle visMoniker,
word textHeight,
GStateHandle gstate,
word yMaximum,
word xMaximum,
word yInset,
word xInset);
This message draws a visual moniker for the object. This message may be called by an object on itself in its
MSG_VIS_DRAW
handler.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
monikerFlags
A record of
DrawMonikerFlags
indicating how the moniker should be drawn. These flags are described below.
visMoniker
textHeight
gstate
MSG_VIS_DRAW
, which invokes this message.
yMaximum
monikerFlags
. Pass MAX_COORD to avoid clipping.
xMaximum
monikerFlags
. Pass MAX_COORD to avoid clipping.
yInset
xInset
Return: Nothing.
Interception: Unlikely.
Structures:
The
DrawMonikerFlags
structure is defined as follows:
typedef ByteFlags DrawMonikerFlags; #define DMF_UNDERLINE_ACCELERATOR 0x40 /* Underlines accelerator key, if any */ #define DMF_CLIP_TO_MAX_WIDTH 0x20 /* Clips the moniker to the xMaximum * parameter */ #define DMF_NONE 0x10 /* Set to draw the moniker at the * current pen position (ignore the * xInset and yInset parameters) */ #define DMF_Y_JUST_MASK 0x0c #define DMF_X_JUST_MASK 0x03 /* These are two bitfields that * determine the justification. * Their offsets are below; they * are of type Justification. */ #define DMF_Y_JUST_OFFSET 2 #define DMF_X_JUST_OFFSET 0
XYValueAsDWord MSG_VIS_GET_MONIKER_POS(@stack
DrawMonikerFlags monikerFlags,
ChunkHandle visMoniker,
word textHeight,
GStateHandle gstate,
word yMaximum,
word xMaximum,
word yInset,
word xInset);
This message returns the position at which the moniker would appear if it were drawn with
MSG_VIS_DRAW_MONIKER
. The moniker is not actually drawn by this message.
Source: Unrestricted.
Destination: Any visible object.
Parameters: See
MSG_VIS_DRAW_MONIKER
above.
Return: A dword value representing the horizontal and vertical positions where the moniker would be drawn if it were drawn with the passed parameters. The horizontal position is returned in the high word; the vertical position is returned in the low word. Use the DWORD_X and DWORD_Y macros to extract the
x
and
y
values. These macros can be found in the file
graphics.h
.
Interception: Unlikely.
SizeAsDWord MSG_VIS_GET_MONIKER_SIZE(@stack
DrawMonikerFlags monikerFlags,
ChunkHandle visMoniker,
word textHeight,
GStateHandle gstate,
word yMaximum,
word xMaximum,
word yInset,
word xInset);
This message returns the size of the moniker specified by the parameters. The moniker is not drawn.
Source: Unrestricted.
Destination: Any visible object.
Parameters: See
MSG_VIS_DRAW_MONIKER
above.
Return: A dword value representing the size of the moniker. The width of the moniker is returned in the high word; the height is returned in the low word. Use the macros DWORD_WIDTH and DWORD_HEIGHT, which can be found in the file visC.goh and also on DWORD_HEIGHT .
Interception: Unlikely.
optr MSG_VIS_FIND_MONIKER(@stack
VisMonikerSearchFlags searchFlags,
MemHandle destBlock,
ChunkHandle monikerList,
DisplayType displayType);
This message locates the given visual moniker list and returns the optr of the moniker most appropriate for the passed display scheme.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
searchFlags
A record of
VisMonikerSearchFlags
(described below) indicating the attributes of the moniker that should be returned.
destBlock
monikerList
displayType
DisplayType
of the moniker to be found (see below).Interception: Unlikely.
Structures:
The
VisMonikerSearchFlags
are listed below.
typedef WordFlags VisMonikerSearchFlags; #define VMSF_STYLE 0xf000 /* Four bits defining the preferred style of * the moniker. These bits are of type * VMStyle, which is defined below. */
#define VMSF_COPY_CHUNK 0x0400 /* Set if the moniker should be copied into * the block specified if not already in * that block. */ #define VMSF_REPLACE_LIST 0x0200 /* Set if the moniker list chunk containing * the VisMoniker should be replaced. The * chunk handle of the list will then point * to the moniker rather than the list. */ #define VMSF_GSTRING 0x0100 /* Set if a GString moniker is expected, * clear if a text moniker is expected. */
/* The remaining bits of this record are * reserved for internal use. */
#define VMSF_STYLE_OFFSET 12
typedef ByteEnum VMStyle; #define VMS_TEXT 0 /* Normal text moniker */ #define VMS_ABBREV_TEXT 1 /* short text abbreviation */ #define VMS_GRAPHIC_TEXT 2 /* textual GString */ #define VMS_ICON 3 /* normal GString moniker */ #define VMS_TOOL 4 /* tool moniker, normally smaller * than a standard moniker */
The
DisplayType
flags are listed below and can be found in win.h:
typedef ByteFlags DisplayType; #define DT_DISP_SIZE 0xc0 /* Two bits indicating the size of the * display; a DisplaySize value, one of * DS_TINY (CGA, or 256 x 320), * DS_STANDARD (EGA, VGA, HGC, MCGA), * DS_LARGE (800 x 600 SVGA), or * DS_HUGE (huge screens). */ #define DT_DISP_ASPECT_RATIO 0x30 /* Two bits indicating the aspect * ratio of the screen; a value of * DisplayAspectRatio, one of * DAR_NORMAL (VGA or MCGA), * DAR_SQUISHED (EGA or HGC), or * DAR_VERY_SQUISHED (CGA) */ #define DT_DISP_CLASS 0x0f /* Four bits indicating the class of * the display driver (or closest * match); A DisplayClass value, one of * DC_TEXT (char only, not implemented), * DC_GRAY_1 (1 bit/pixel gray scale), * DC_GRAY_2 (2 bit/pixel gray scale), * DC_GRAY_4 (4 bit/pixel gray scale), * DC_GRAY_8 (8 bit/pixel gray scale), * DC_COLOR_2 (2 bit/pixel color index), * DC_COLOR_4 (4 bit/pixel color index), * DC_COLOR_8 (8 bit/pixel color index), * DC_CF_RGB (color with RGB values) */
ChunkHandle MSG_VIS_CREATE_VIS_MONIKER(@stack
CreateVisMonikerFlags flags,
word height,
word width
word length,
VisMonikerDataType dataType,
VisMonikerSourceType sourceType,
dword source);
This message creates a new chunk for a visual moniker within the recipient's object block. The new moniker can be created from an already existing visual moniker, a visual moniker list, a text string, a GString, or a token from the token database. The source may be defined by a far pointer, a global memory handle, or an optr. If the source is a text string or GString, a visual moniker structure will be created for the string. The newly-created chunk is marked dirty if the CVMF_DIRTY flag is passed.
If a moniker list is passed, the entire list will be copied into the destination object block. You must make sure that all the monikers in the list will still exist when the list is used.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
flags
A record of
CreateVisMonikerFlags
. Currently only one may be passed: CVMF_DIRTY, which indicates that the chunk should be marked dirty.
height
width
length
dataType
VisMonikerDataType
. This parameter determines the type of moniker to be created.
sourceType
VisMonikerSourceType
.
source
sourceType
.Return: The chunk handle of the new visual moniker. The visual moniker chunk resides in the object block of the object receiving the message. If the flag CVMF_DIRTY is passed, the chunk will be marked dirty.
Interception: Unlikely--custom UI gadgets may intercept in some cases.
Structures:
VisMonikerSourceType
and
VisMonikerDataType
are defined below. Both can be found in
visC.goh
.
typedef ByteEnum VisMonikerSourceType; #define VMST_FPTR 0 /* Source is referenced by a pointer. * CVMF_source is a far pointer. */ #define VMST_OPTR 1 /* Source is referenced by an optr. * CVMF_source is an optr. */ #define VMST_HPTR 2 /* Source is referenced by a combination * memory handle and offset into the * memory block (as opposed to an optr * in which the low word is actually a * chunk handle, not an offset). */
typedef ByteEnum VisMonikerDataType; #define VMDT_NULL 0 /* There is no source. Not valid for * MSG_VIS_CREATE_VIS_MONIKER. */ #define VMDT_VIS_MONIKER 1 /* Source is a complete VisMoniker * structure. CVMF_length indicates the * size of a complete VisMoniker * structure; CVMF_width and * CVMF_height are unused. */ #define VMDT_TEXT 2 /* Source is a text string. If the * string is null-terminated, * CVMF_length should be zero. * Otherwise, CVMF_length is the length * of the string; A VisMoniker * structure will be created for the * string. CVMF_width and CVMF_height * are unused. */ #define VMDT_GSTRING 3 /* Source is a GString. If CVMF_length * is zero, the GString length is * determined by scanning for * GR_END_STRING. Otherwise, CVMF_length * indicates the length of the GString. * CVMF_width and CVMF_height indicate * the width and height of the GString. * If either is zero, the dimension will * be calculated by examining the * string. A VisMoniker structure will * be created for the GString. */ #define VMDT_TOKEN 4 /* Source is a GeodeToken. CVMF_length, * CVMF_width, and CVMF_height are * unused. The destination must be able * to use this data type because the * specific UI must decide which moniker * to choose from the token in the token * database. */
word DWORD_HEIGHT(val);
dword val;
This macro extracts the height from a
SizeAsDWord
structure (dword).
word DWORD_WIDTH(val);
dword val;
This macro extracts the width from a
SizeAsDWord
structure (dword).
SizeAsDWord MAKE_SIZE_DWORD(width, height);
word width, height;
This macro takes a width and height and creates a
SizeAsDWord
value.
MSG_VIS_CREATE_CACHED_GSTATES, MSG_VIS_RECREATE_CACHED_GSTATES, MSG_VIS_DESTROY_CACHED_GSTATES
Many complex visible objects (such as VisText and VisSpline) have both a cached GState and a reference count. When the reference count goes from zero to one, the Vis object creates and caches a GState; when the reference count goes from one to zero, the cached GState is destroyed.
VisClass
has three messages to create, update, and destroy the cached GStates. None of these messages has any default behavior; they are provided for complex objects to handle should they need them.
void MSG_VIS_CREATE_CACHED_GSTATES();
This message may be used to create and cache a GState, typically to avoid having a complex Vis object update several times for several simple operations (such as pointer events).
Source: Unrestricted.
Destination: Any visible object.
Interception: Must be intercepted to have any effect; there is no default behavior.
void MSG_VIS_RECREATE_CACHED_GSTATES();
This message may be used to have the Vis object destroy and recreate any cached GStates it has. For example, cached GStates of a complex visible object that gets moved or resized will no longer map to the proper place in the object's document. After the move or resize, this message may be used to update those GStates.
Source: Unrestricted.
Destination: Any visible object.
Interception: Must be intercepted to have any effect; there is no default behavior.
void MSG_VIS_DESTROY_CACHED_GSTATES();
This message may be used to destroy any cached GStates the visible object may have.
Source: Unrestricted.
Destination: Any visible object.
Interception: Must be intercepted to have any effect; there is no default behavior.
Every visible object has an instance data field called
VI_bounds
that records the object's visible bounds. Visible bounds are the left, top, right, and bottom bounds of a rectangle that define the maximum area covered by the visible object. The bounds are used primarily for determining the object's size and location.
The
VI_bounds
field is a
Rectangle
structure, provided by the graphics system. This structure has four components, as shown below:
typedef struct {
sword R_left; /* x of upper-left corner */
sword R_top; /* y of upper-left corner */
sword R_right; /* x of lower-right corner */
sword R_bottom; /* y of lower-right corner */
} Rectangle;
The bounds of non-window objects are stored in document coordinates relative to the document displayed by the window in which they appear. The left and top bounds constitute the position of the object. The difference between the right and left bounds is the object's width; the difference between bottom and top is its height. Together, the width and height constitute the object's size.
The bounds of a window or portal object (VTF_IS_WINDOW or VTF_IS_PORTAL) represent the location of the window, in document coordinates, within its parent window. The coordinate system within the window object is independent from that of its parent.
Unless an object's bounds are set in the Goc code, they will be set at zero and must be initialized to some values before the object can be drawn. This initialization can be done with the messages that set position and size, or it can be done automatically by the geometry manager (if a composite is managing its children).
The
VI_bounds
instance field exists in
VisClass
and therefore occurs also in
VisCompClass
and
VisContentClass
and all their subclasses. Any object can directly set any or all of its bounds; other objects (such as a parent VisComp) can direct the object to set its bounds to certain coordinates as a result of either geometry management or some user action. For example, a VisComp that has ten children may recalculate their positions if one of those children gets resized; the composite must then notify all the children of their new positions. To learn how a composite object can manage its children in different ways, see the VisComp chapter.
MSG_VIS_GET_POSITION, MSG_VIS_SET_POSITION, MSG_VIS_GET_BOUNDS
An object's bounds determine both the location and the size of the object in the document space. The object may reposition itself or resize itself at will; for example, it may allow the user to move or resize it with the mouse. The object can also receive direction from other objects that it should change its bounds. Note that none of these messages by themselves will cause the object to redraw; you must also send a
MSG_VIS_MARK_INVALID
to the object to get either its geometry or its image to be marked invalid.
An object's position is represented by the upper-left corner of its bounds, defined by
VI_bounds
.
R_top
and
VI_bounds
.
R_left
. You can retrieve an object's position by sending it
MSG_VIS_GET_POSITION
, or you can set it with
MSG_VIS_SET_POSITION
. You can also use
MSG_VIS_GET_BOUNDS
to get all four components of the object's bounds.
An object can access its own bounds field with a simple pointer. Since every message has
pself
as an implicit parameter (a pointer to the object's instance data structure), any object can look at or change its bounds directly. (See the example in Grabbing and Releasing the Mouse
.)
Using Swat, you can see a visible object's bounds with the command
pobj
.
If you have a composite object managing several children, you can arrange to have their positions determined automatically. This is discussed in Geometry Management .
void MSG_VIS_SET_POSITION(
int xOrigin,
int yOrigin);
This message causes the object to set its
VI_bounds
to the new location specified, retaining its current size. The left bound (
VI_bounds
.
R_left
) is set to the value of
xOrigin
, and the top bound (
VI_bounds
.
R_top
) is set to that of
yOrigin
. The right and bottom bounds are set to match the new origin and the width and height of the object.
Source: Unrestricted--usually the visible parent or geometry manager.
Destination: Any visible object.
Parameters:
xOrigin
New horizontal coordinate of the object's position.
yOrigin
Return: Nothing.
Interception: Unlikely. It's much more likely that the object will subclass
MSG_VIS_POSITION_BRANCH
.
Warnings: This message will not cause an image invalidation. You must mark the object invalid with
MSG_VIS_MARK_INVALID
.
See Also:
MSG_VIS_POSITION_BRANCH
,
MSG_VIS_MARK_INVALID
.
XYValueAsDWord MSG_VIS_GET_POSITION();
This message returns the current origin of the object. The origin returned consists of the left and top object bounds (
VI_bounds
.
R_left
and
VI_bounds
.
R_top
, respectively).
Source: Unrestricted.
Destination: Any visible object.
Parameters: None.
Return: A dword value representing the left bound in the low word and the top bound in the high word. Use the macros DWORD_X and DWORD_Y to extract the bounds from the return value (see the file graphics.h ).
Interception: Unlikely.
void MSG_VIS_GET_BOUNDS(
Rectangle *retValue);
This message returns the current rectangle structure stored in the object's
VI_bounds
field. This rectangle represents both the position and the size of the object by giving its left, top, right, and bottom bounds.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
retValue
A pointer to an empty
Rectangle
structure. The values in the object's
VI_bounds
field will be returned in the structure pointed to.
Return: The
retValue
pointer will be returned with the bounds filled into the
Rectangle
structure.
Interception: Unlikely.
MSG_VIS_GET_SIZE, MSG_VIS_SET_SIZE
A visible object's size is defined as its width and height. The width is the difference between the object's left and right bounds; the height is the difference between the object's top and bottom bounds.
You can retrieve a visible object's size with the message
MSG_VIS_GET_SIZE
, and you can set it with
MSG_VIS_SET_SIZE
.
MSG_VIS_SET_SIZE
will set the object's right and bottom bounds without recalculating the object's position. If geometry is being managed automatically, you may want to subclass other messages; these are described in Geometry Management
.
In Swat, you can see the object's size indirectly with the command
pobj
. This command will show, among other things, the
VI_bounds
field of the object. You can manually calculate the size from that information.
void MSG_VIS_SET_SIZE(
int width,
int height);
This message sets the object's height and width to the passed values, retaining the object's current position. The object's position will not be recalculated as a result of the size change.
Source: Unrestricted--usually the geometry manager or the object's visible parent calculating geometry.
Destination: Any visible object.
Parameters:
width
The new width of the object.
width
will be added to the object's left bound to get the object's new right bound.
height
height
will be added to the object's top bound to get the object's new bottom bound.Return: Nothing.
Interception: Unlikely.
Warnings: This message will not cause an image invalidation. You must mark the object invalid with
MSG_VIS_MARK_INVALID
.
SizeAsDWord MSG_VIS_GET_SIZE();
This message returns the current size (width and height) of the object. Both values are word-sized integers and are returned in a single dword value. The high word of this value is the object's width, and the low word is the object's height.
Source: Unrestricted.
Destination: Any visible object.
Parameters: None.
Return: A dword value representing the object's width in the low word and height in the high word. Use the macros DWORD_WIDTH and DWORD_HEIGHT to extract the width and height; see DWORD_HEIGHT .
Interception: Unlikely.
MSG_VIS_UPDATE_GEOMETRY, MSG_VIS_NOTIFY_GEOMETRY_VALID, MSG_VIS_RECALC_SIZE, MSG_VIS_GET_CENTER, MSG_VIS_RECALC_SIZE_AND_INVAL_IF_NEEDED, MSG_VIS_RESET_TO_INITIAL_SIZE, MSG_VIS_POSITION_BRANCH, MSG_VIS_POSITION_AND_INVAL_IF_NEEDED, MSG_VIS_INVAL_ALL_GEOMETRY
Geometry management consists of positioning and sizing visible objects properly. This can be done manually by the programmer or automatically by GEOS. If you wish to manually control your visible tree's geometry, set the flag VCGA_CUSTOM_MANAGE_CHILDREN in the top composite's
VCI_geoAttrs
field (see the VisComp chapter). You can then use any messages, either native to VisClass
or defined by your subclasses, for object positioning and sizing.
Automatic geometry management occurs when the geometry of the visible tree is marked invalid somewhere and a visual update is initiated. The tree's geometry can be marked invalid in several ways--an object can be added to or removed from the tree, an object can be manually marked invalid (with
MSG_VIS_MARK_INVALID
), or an object can be opened or closed (
MSG_VIS_OPEN
or
MSG_VIS_CLOSE
).
When automatic geometry management is invoked, the geometry manager will recalculate the entire affected branch's geometry. It will calculate geometry for each affected window group, from the topmost affected window object down to the bottommost affected object. If the geometry manager encounters window groups below the topmost window, it will check first to see if the lower window's size is controlled by its children (e.g., a GenView that follows the geometry of its content). If the lower window is scrollable or otherwise not subject to its children's geometry, the geometry manager will finish calculating the geometry above the lower window before proceeding.
Calculating geometry is an involved, complex task. The process involves composites and their children negotiating on desired sizes. How the geometry is calculated depends primarily on the relationships between the objects and how their flags are set.
For example, if a GenView is set up to be exactly the same size as its VisContent object, the calculations will be different than if the GenView were scrollable. The same is true for visible composites that manage their children: If the composite resizes itself large enough to hold all its children, the children must be resized first.
The negotiation between parent and child in the visible tree takes the form of a single message:
MSG_VIS_RECALC_SIZE
. This is the single most important message in calculating the tree's geometry, though others are also significant. This message is sent by a composite to each of its children in turn; it passes a suggested size, and the child returns its desired size.
The composite collects all the desired sizes of its children and compares that to the size it thinks it should be. If necessary, it makes another pass through the children, or it passes on its desired size to its parent composite. Depending on the situation and the disparity between parent and children sizes, the geometry calculation may take a single pass or several. If the sizes can not be resolved through this negotiation, the geometry manager will make a decision after several passes, typically expanding the parent as much as possible to fit all the children.
After a visible object has calculated its size, its size will be set either by itself or by its parent. Often this is done with
MSG_VIS_SET_SIZE
. Once all sizes have been determined and set, the objects set their positions with
MSG_VIS_POSITION_BRANCH
, which propagates down the tree. It sets the position of the topmost composite and then sets each of its children's positions appropriately.
When geometry calculations are complete, the geometry manager will send a
MSG_VIS_NOTIFY_GEOMETRY_VALID
to all visible objects with the flag VGA_NOTIFY_GEOMETRY_VALID set in its
VI_geoAttrs
field.
Several other messages may be used during geometry updates. Some of them may be intercepted to alter the behavior of the default method. These messages are listed below. Others can be used to invalidate a visible object's geometry or to cause a geometry update on the tree.
MSG_VIS_UPDATE_GEOMETRY
MSG_VIS_NOTIFY_GEOMETRY_VALID
VI_geoAttrs
field. There is no default behavior for this message; it should be intercepted only if the object needs to do calculations after the geometry has settled down.
MSG_VIS_RECALC_SIZE
MSG_VIS_RECALC_SIZE_AND_INVAL_IF_NEEDED
MSG_VIS_RECALC_SIZE
. Composites should use this version when sending a recalculation message to their children. This message only causes recalculation if needed and will invalidate the object if the size gets recalculated. It invalidates the object's image at its old bounds and only invalidates its geometry if the bounds change. It is highly unlikely that you'll subclass this method.
MSG_VIS_GET_CENTER
MSG_VIS_RESET_TO_INITIAL_SIZE
VI_geoAttrs
field, causing the object to believe it is being put on-screen for the first time. This message will also set the object's flags to indicate that its geometry has become invalid. It's highly unlikely your application will subclass this method.
MSG_VIS_POSITION_BRANCH
VisCompClass
and perhaps
VisContentClass
will change this method.
MSG_VIS_POSITION_AND_INVAL_IF_NEEDED
MSG_VIS_POSITION_BRANCH
that causes a branch reposition only if it's necessary. It will also invalidate both the object's and the parent's original images and, if the position changes, the geometry as well. It is highly unlikely that you'll subclass this method.
MSG_VIS_INVAL_ALL_GEOMETRYvoid MSG_VIS_UPDATE_GEOMETRY();
This message is sent during a visual update to cause objects to recalculate their geometry. Applications can use this message to ensure that geometry gets updated for a visual branch even if the branch is not currently drawn on the screen.
Source: Visual update mechanism.
Destination: Any visible object.
Interception: May be intercepted for optimizations. A thorough knowledge of the geometry update mechanism and the specifics of the visible tree's geometry is strongly recommended, however.
void MSG_VIS_NOTIFY_GEOMETRY_VALID();
This message is sent by the geometry manager to objects that have VGA_NOTIFY_GEOMETRY_VALID set. The message is sent only after all geometry messages have been handled for the object. It has no default behavior.
Source: Visible update mechanism.
Destination: Any visible object--typically a child of the object sending the message.
Interception: This message has no default behavior. It should be intercepted by any object that needs to do something after its geometry has been made valid.
SizeAsDWord MSG_VIS_RECALC_SIZE(
int width,
int height);
This message takes the suggested height and width of the object and recalculates the object's desired size based on them. Composite objects are expected to pass this message to their children and then calculate their sizes based on those of their children. The default behavior of the handler for this is to return the current size no matter what the suggested size is.
Source: Visible update mechanism.
Destination: Any visible object.
Parameters:
width
Suggested new width of the object as determined by the object's parent.
height
Return: A dword value representing the object's desired size as calculated by the object. The high word of the return value represents the width and the low word the height. Use the macros DWORD_WIDTH and DWORD_HEIGHT to extract the width and height; see DWORD_HEIGHT .
Interception: Default behavior is to return the object's current size no matter what the passed width and height are. Any object that wants special sizing behavior based either on the object's children or on the suggested size should subclass the method.
SizeAsDWord MSG_VIS_RECALC_SIZE_AND_INVAL_IF_NEEDED(
int width,
int height);
This message is the same as
MSG_VIS_CALC_RESIZE
except that it is somewhat optimized. It will recalculate only if certain flags are set for the object, and it will mark the geometry invalid only if recalculation is done.
Source: Visible update mechanism.
Destination: Any visible object.
Parameters:
width
Suggested new width of the object as determined by the object's parent.
height
Return: A dword value representing the object's desired size as calculated by the object. The low word of the return value represents the width and the high word the height.
Interception: Unlikely--Default behavior is to return the object's current size no matter what the passed width and height are. Any object that wants special sizing behavior based either on the object's children or on the suggested size should subclass the method.
void MSG_VIS_GET_CENTER(
GetCenterParams *retValue);
This message returns the amount of space needed by the object in each direction from its center. It does not, as the name suggests, return the coordinates of the center of the object. Instead, the object must determine the amount of space it requires from its center to each edge for geometry management and return them in the structure passed.
Source: Visible update mechanism.
Destination: Any visible object
Parameters:
retValue
A pointer to an empty
GetCenterParams
structure, defined below.
Return: The method must fill the
GetCenterParams
structure pointed to by the
retValue
parameter.
Interception: Any object that wants to effect a different centering than the default should subclass this method. For example, if a set of objects can be overlapped, or if they should have extra space between them, they should subclass this message and alter the returned values appropriately.
Structures:
The
GetCenterParams
structure is defined as follows:
typedef struct {
word GCP_aboveCenter; /* space above */
word GCP_belowCenter; /* space below */
word GCP_leftOfCenter; /* space left */
word GCP_rightOfCenter; /* space right */
} GetCenterParams;
void MSG_VIS_RESET_TO_INITIAL_SIZE(
VisUpdateMode updateMode);
This message propagates down an entire visual branch, causing the objects in it to reset their sizes to their original width and height. First it invalidates the object's geometry, then it recalculates the geometry starting at the top.
Source: Visible update mechanism.
Destination: Any visible object.
Parameters:
updateMode
A
VisUpdateMode
indicating when the visual update of the tree should occur.
Return: Nothing.
Interception: Unlikely.
void MSG_VIS_POSITION_BRANCH(
word xOrigin,
word yOrigin);
This message repositions an entire visible branch. It propagates down the branch, causing each visible object to reposition itself based on the new origins passed. Composites must pass the appropriate altered positions to their children.
Source: Visible update mechanism.
Destination: Any visible object.
Parameters:
xOrigin
The new horizontal position of the object relative to the document or window it's in. This value is set into the object's
VI_bounds
.
R_left
bound, and the right bound is set according to the object's size.
yOrigin
VI_bounds
.
R_top
bound, and the bottom bound is set according to the object's size.Return: Nothing.
Interception: The default behavior is to set the object to the passed position. Composite objects that want to position their children a special way should subclass this (and not call the superclass) method. Non-composites will rarely, if ever, subclass this message.
Boolean MSG_VIS_POSITION_AND_INVAL_IF_NEEDED(
word xPosition,
word yPosition);
This message is an optimized version of
MSG_VIS_POSITION_BRANCH
. It repositions the branch only if necessary and will mark the image invalid only if the position was changed. It returns a flag indicating whether or not the object was repositioned.
Source: Visible update mechanism.
Destination: Any visible object--typically sent by a composite to its children.
Parameters:
xPosition
The new horizontal position of the object relative to the document or window it's in. A negative value means that the object should choose its own position as best it can.
yPosition
Return: If the object was repositioned, the message will return
true
. Otherwise, it will return
false
.
Interception: Unlikely.
void MSG_VIS_INVAL_ALL_GEOMETRY(
VisUpdateMode updateMode);
This is a brute-force, desperation message used to invalidate all geometry in the recipient's tree; that is, all geometry of the recipient and all objects under it in the tree will be invalidated. You should only use this message when the whole tree should be recalculated.
Source: Unrestricted.
Destination: The object requiring geometry recalculation.
Parameters:
updateMode
A visual update mode indicating when the visual update of the recalculation should occur.
Return: Nothing.
Interception: Generally not intercepted.
Input events, what they mean, and how they are generated are discussed fully in the Input chapter. The visible world has some default behavior for handling input messages such as MSG_META_START_SELECT
,
MSG_META_END_SELECT
, and
MSG_META_PTR
. For the most part, however, visible objects that want to respond to input must subclass and handle the input messages that interest them.
Composite objects will automatically pass mouse messages on to the proper child directly under the mouse pointer. Non-composite objects (direct subclasses of
VisClass
) have no special default behavior for input handling.
Note that
VisClass
does not intelligently handle layering of objects. That is, if one object is visibly on top of another object, it will not necessarily receive the input events--the events may be passed to the partially hidden object. This is due to the order in which drawing and mouse events are handled by a visible object's children.
Take the example of a visible composite with two children. Each child draws a filled rectangle covering its bounds; the first child has a width and height of 40, and the second child has a width and height of 20. The composite's declaration shows
...
VCI_comp = LargeChild, SmallChild;
...
Because drawing occurs in the order the children are listed, the small child will be drawn over the large child, as shown in the figure below. If each object can intercept and handle mouse events (e.g.,
MSG_META_START_SELECT
), clicks will never reach the small object without special behavior added to the composite. This is because input events are handled in the same order as drawing; the input event will be given to the first child whose bounds include the event's coordinates.
So, a click event on (10, 10), which is in the middle of the small square, would first be passed to the LargeChild object. The large child would see that the click was within its bounds, and it would take the event. The event would never be handled by the small object.
Therefore, if you need to have overlapping objects which handle user input, you will have to add special features for bounds detection. In the example of the two squares, if neither were to move, the composite could simply pass the event to the small child first and then to the large child, assuming the small child is always on top. If the objects could be moved forward and back so they hide each other, the composite (or the objects themselves) will need some other, more complex, detection behavior.
MSG_META_PTR, MSG_META_START_SELECT, MSG_META_END_SELECT, MSG_META_DRAG_SELECT, MSG_META_DRAG, MSG_META_START_MOVE_COPY, MSG_META_DRAG_MOVE_COPY, MSG_META_START_OTHER, MSG_META_END_OTHER, MSG_META_DRAG_OTHER
Composite objects will automatically pass mouse messages on to the first child directly under the mouse pointer. Non-composite objects (direct subclasses of
VisClass
) have no special default behavior for input handling.
Typically, a visible object that needs to handle mouse input will subclass
MSG_META_START_SELECT
(or one of the other press events such as
MSG_META_START_MOVE_COPY
). This message is sent when the user presses on the "select" mouse button while the pointer is over the object. In this method, the object should grab the mouse (as shown below). When it has the mouse grab, it will receive
MSG_META_PTR
each time the mouse is moved; the object should subclass this message to provide the desired reaction to mouse moves. Finally, when the user releases the select button, the object will receive a
MSG_META_END_SELECT
. At this point, it should release the mouse grab.
Typically, mouse events will arrive with coordinates specified in 16 bits. This is the default graphics space, and it represents a coordinate system more than 25 yards on a side. Nearly all applications will find this graphic system big enough for their uses. However, if you need larger coordinates, you can use the large document space with 32-bit coordinates. To do this, you must set the GVA_WINDOW_COORDINATE_MOUSE_EVENTS in the
GVI_attrs
field of your GenView object and set up your visible objects correctly. For more information on supporting 32-bit graphic spaces with visible objects, see Visible Layers and 32-Bit Graphics
.
MSG_VIS_GRAB_MOUSE, MSG_VIS_FORCE_GRAB_MOUSE, MSG_VIS_GRAB_LARGE_MOUSE, MSG_VIS_FORCE_GRAB_LARGE_MOUSE, MSG_VIS_RELEASE_MOUSE
When an object "grabs the mouse," it requests that the UI send all future mouse events directly to that object. Normally, mouse events will travel down the visible object tree until they reach either the leaf object under the pointer or an object under the pointer that handles them. When an object has the mouse grab, the mouse events will go to the object with the grab regardless of the location of the pointer.
Typically, if an object wants to receive mouse events, it will subclass
MSG_META_START_SELECT
. This message is sent to the object when the pointer is over the object's bounds and the user presses the select button. In this handler, the object grabs the UI's gadget exclusive and then grabs the mouse. A good example of this can be found in the TicTac sample application's handler for
MSG_META_START_SELECT
.
After an object grabs the mouse, it receives all pointer and drag events that occur. These are primarily
MSG_META_PTR
messages, and the object must subclass
MSG_META_PTR
to achieve the proper behavior it wants. When the user lets go of the select button, the object will receive a
MSG_META_END_SELECT
. If it grabbed the mouse (which it probably did if it receives this message), it must relinquish both the gadget exclusive and its mouse grab.
An example of getting and releasing the mouse grab (taken from the TicTac sample application) is shown in Grabbing and Releasing the Mouse . The object subclasses these messages to let the user drag it around the screen.
The UI allows the visible object to get the normal mouse grab by using four different messages. Each of these is detailed below. If you're using a large document (32-bit coordinates), you will use the "large" mouse grabs. Otherwise, the normal mouse grab messages will do.
void MSG_VIS_GRAB_MOUSE();
A visible object sends itself this message (with
@call
) when it wants to acquire the normal mouse grab. The message
MSG_VIS_RELEASE_MOUSE
must be used to relinquish the grab.
Source: Unrestricted.
Destination: Any visible object--typically sent by the object to itself.
Interception: Highly unlikely.
void MSG_VIS_FORCE_GRAB_MOUSE();
A visible object sends itself this message (with
@call
) when it wants to forcibly grab the mouse input. The object will acquire the mouse grab even if another object currently has it; the other object will receive a
MSG_VIS_LOST_GADGET_EXCL
when it loses the mouse by a forced grab. The object must release the grab later with
MSG_VIS_RELEASE_MOUSE
.
Source: Unrestricted.
Destination: Any visible object--typically sent by the object to itself.
Interception: Highly unlikely.
void MSG_VIS_GRAB_LARGE_MOUSE();
A visible object sends itself this message (with
@call
) when it wants to acquire the mouse grab and when it wants 32-bit coordinates. If the object wants 16-bit coordinates, it should use
MSG_VIS_GRAB_MOUSE
, above. The object must relinquish the mouse grab with
MSG_VIS_RELEASE_MOUSE
.
Source: Unrestricted.
Destination: Any visible object--typically sent by the object to itself.
Interception: Highly unlikely.
void MSG_VIS_FORCE_GRAB_LARGE_MOUSE();
A visible object sends itself this message (with
@call
) when it wants to forcibly grab the mouse input and when it wants large (32-bit) input coordinates. If it wants normal (16-bit) coordinates, it should use
MSG_VIS_FORCE_GRAB_MOUSE
, above. The object will acquire the mouse grab even if another object currently has it; the other object will receive a
MSG_VIS_LOST_GADGET_EXCL
when it loses the mouse by a forced grab. The object must release the grab later with
MSG_VIS_RELEASE_MOUSE
.
Source: Unrestricted.
Destination: Any visible object--typically sent by the object to itself.
Interception: Highly unlikely.
void MSG_VIS_VUP_ALTER_INPUT_FLOW(@stack
PointDWord translation,
WindowHandle window,
optr object,
word grapTypeAndFlags);
This message is the primitive employed by the grab/release messages shown above. Objects will rarely use this unless they are large objects (using 32-bit coordinates). Large objects and composites should subclass this message. In the case of a mouse grab, they should add in their 32-bit offset amounts to the translation structure before passing the event on to their superclasses. This will result in large mouse events being properly translated for the duration of the mouse grab.
Source: Unrestricted.
Destination: Any visible object--typically a VisContent which uses a 32-bit graphics space for its children.
Parameters:
translation
The offsets to the origin of the "local" 16-bit graphics space.
window
object
grabTypeAndFlags
VisInputFlowGrabType
, described below; the low byte contains a
VisInputFlowGrabFlags
record, also described below.Return: Nothing.
Interception: Any VisContent object that uses a large graphics space should subclass this method. In the handler, it should apply the stated translation, then call its superclass. Each subsequent mouse event will have the translation applied before being passed on to the composite's children.
Structures:
The types of
VisInputFlowGrabType
are listed below:
VisInputFlowGrabFlags
are listed below:
object
must be passed--if a release, the grab will not be released unless the objects match. Note also that only one object may have the active grab, but many objects may have either passive grab at a given time.void MSG_VIS_RELEASE_MOUSE();
A visible object sends itself this message if it has the mouse grab and wants to release it. Typically, this message will be called in the object's
MSG_META_END_SELECT
handler. It works for both large and small grabs.
Source: Any visible object.
Destination: Any visible object--typically sent by the object to itself.
Interception: Unlikely.
Code Display 15-2 Grabbing and Releasing the Mouse
/* This code display shows the MSG_META_START_SELECT, MSG_META_END_SELECT, * and MSG_VIS_LOST_GADGET_EXCL handlers from the TicTac sample application. * * The sequence of input events and the messages they generate follow the * following basic patterns: * 1. User presses select button * MSG_META_START_SELECT generated, sent to object under mouse pointer * If object under pointer is a game piece, * Game piece grabs gadget exclusive * Game piece grabs mouse * 2. User holds button and drags mouse * MSG_META_DRAG_SELECT generated, sent to object with mouse grab * Game piece sets internal "dragging" flag * Game piece draws outline * MSG_META_PTR messages generated during drag, sent to object with mouse grab * Game piece erases previous outline * Game piece draws new outline at new pointer position * 3. User releases button * MSG_META_END_SELECT generated, sent to object with mouse grab * Game piece releases gadget exclusive (MSG_VIS_RELEASE_GADGET_EXCL) * MSG_VIS_LOST_GADGET_EXCL generated, sent to mouse grab (game piece) * Game piece erases old outline, if any * Game piece moves itself, erases old bounds, draws new bounds * Game piece releases mouse grab (MSG_VIS_RELEASE_MOUSE) */
/*********************************************************************** * MSG_META_START_SELECT for TicTacPieceClass *********************************************************************** * SYNOPSIS: Grabs the mouse and calls for future pointer events. * When the user clickes in the view, TicTacView will pass * the click event to TicTacBoard. Since TicTacBoardClass * does not intercept the event, VisContentClass passes * it on to its child object currently under the pointer. * PARAMETERS: * void (MouseReturnParams *retVal, * word xPosition, word yPosition, word inputState); * * STRATEGY: When the piece object receives this message, it means * it has been clicked on by the user and the mouse button * is still down. The piece must grab the mouse so that it * gets all future mouse events, and it must request that * all future mouse events be sent to it. This ensures * that if the pointer leaves the object's bounds while * the button is still pressed, the piece object will still * receive all the pointer events (otherwise they would be * sent to whatever object was under the new pointer position). ***********************************************************************/
@method TicTacPieceClass, MSG_META_START_SELECT {
/* Grab the gadget exclusive so we're allowed to grab the mouse. */
@call @visParent::MSG_VIS_TAKE_GADGET_EXCL(oself);
/* Grab the mouse. This requests that all future pointer
* events be passed directly to this game piece. */
@call self::MSG_VIS_GRAB_MOUSE();
/* Finally, return that this particular click event has been processed.
* If this flag is not returned, the system will send out the click
* event again. */
retVal->flags = MRF_PROCESSED; /* this event processed */
}
/*********************************************************************** * MSG_META_END_SELECT for TicTacPieceClass *********************************************************************** * SYNOPSIS: This message is received when the selection button has * been released and this game piece had the mouse grab. * All it does is release the gadget exclusive. * PARAMETERS: * void (MouseReturnParams *retVal, * word xPosition, word yPosition, word inputState); ***********************************************************************/
@method TicTacPieceClass, MSG_META_END_SELECT {
@call @visParent::MSG_VIS_RELEASE_GADGET_EXCL(oself);
retVal->flags = MRF_PROCESSED; /* this event processed */
}
/*********************************************************************** * MSG_VIS_LOST_GADGET_EXCL for TicTacPieceClass *********************************************************************** * SYNOPSIS: This message is received when the selection button has * been released and this game piece had the mouse grab. * It first checks to see if the new, proposed bounds are * on the game board. If the bounds are valid, then * it sets the objects VI_bounds field to the new values * and causes the object to erase its original drawing * and draw itself at its new bounds. If the bounds are * not on the game board, it will retain the original bounds * and redraw using them. * PARAMETERS: void (); ***********************************************************************/
@method TicTacPieceClass, MSG_VIS_LOST_GADGET_EXCL {
WindowHandle win; /* window handle of view window */
GStateHandle gstate; /* temporary gstate to draw to */
/* See if piece was being dragged or not. If so, clear the outline. */
if (pself->TTP_dragging) {
/* Get the window handle of the view window and create a * temporary gstate for it to draw to. */
win = @call TicTacView::MSG_GEN_VIEW_GET_WINDOW(); gstate = GrCreateState(win);
/* Set the line color and mode for drawing the outline. */
GrSetLineColor(gstate, CF_INDEX, C_BLACK, 0, 0); GrSetMixMode(gstate, MM_INVERT);
/* Erase outline on screen. */
/* If the game piece type is TTPT_BOX, draw a rectangle * outline. Otherwise draw an ellipse outline. */
if (pself->TTP_pieceType == TTPT_BOX) {
GrDrawRect(gstate, pself->TTP_horizPos, pself->TTP_vertPos,
((pself->TTP_horizPos) + PIECE_WIDTH),
((pself->TTP_vertPos) + PIECE_HEIGHT));
} else {
GrDrawEllipse(gstate, pself->TTP_horizPos, pself->TTP_vertPos,
((pself->TTP_horizPos) + PIECE_WIDTH),
((pself->TTP_vertPos) + PIECE_HEIGHT));
}
/* Check to see if the new bounds are on the game board. If * they are, set the object's bounds to the new values. If * the are not, retain the original values and set the values * to those last stored. */
if (@call TicTacBoard::MSG_TICTAC_VALIDATE_BOUNDS(
((pself->TTP_vertPos) + PIECE_HEIGHT),
((pself->TTP_horizPos) + PIECE_WIDTH),
pself->TTP_vertPos, pself->TTP_horizPos)) {
/* Invalidate the original drawing of the game piece. Send * the VI_bounds rectangle as the parameters because they have * not been changed since the START_SELECT. This message is * the equivalent of calling GrInvalRect() with the same bounds */
@call self::MSG_VIS_BOUNDS_CHANGED(pself->VI_bounds.R_bottom, pself->VI_bounds.R_right, pself->VI_bounds.R_top, pself->VI_bounds.R_left);
/* Set the game piece object's bounds to the new coordinates. */
pself->VI_bounds.R_left = pself->TTP_horizPos; pself->VI_bounds.R_right = (pself->TTP_horizPos) + PIECE_WIDTH; pself->VI_bounds.R_top = pself->TTP_vertPos; pself->VI_bounds.R_bottom = (pself->TTP_vertPos) + PIECE_HEIGHT;
} else {
/* If the bounds are not on the game board, then reset the * current positions to be the original bounds. */
pself->TTP_horizPos = pself->VI_bounds.R_left; pself->TTP_vertPos = pself->VI_bounds.R_top; }
/* Now, the game piece must draw itself at its newly-set * bounds (will draw itself over its original picture if the * new bounds were invalid). */
@call self::MSG_VIS_DRAW(0, gstate);
/* Finally, destroy the temporary gstate used for drawing. */
GrDestroyState(gstate);
/* Clear flag to indicate we are no longer dragging. */
pself->TTP_dragging = FALSE;
}
/* Release the mouse grab now that the move has finished.
* Other objects in the view (other game pieces, for example)
* may now receive pointer, select, and drag events. */
@call self::MSG_VIS_RELEASE_MOUSE(); }
MSG_VIS_ADD_BUTTON_PRE_PASSIVE, MSG_VIS_REMOVE_BUTTON_PRE_PASSIVE, MSG_VIS_ADD_BUTTON_POST_PASSIVE, MSG_VIS_REMOVE_BUTTON_POST_PASSIVE
The type of mouse grab described in the previous section is also known as an "active" mouse grab. An object can also have two other types of mouse grabs: pre-passive and post-passive . While only one object may have the active mouse grab at any given time, any number of objects may have pre- or post-passive grabs on the mouse.
An object with a pre-passive mouse grab receives a copy of the input event before the event goes to its true destination. The copy will be a message of the form
MSG_META_PRE_PASSIVE_...
(e.g., if the event is
MSG_META_PTR
, the pre-passive event is
MSG_META_PRE_PASSIVE_PTR
). All pre-passive events will be handled before the true event is delivered to the object with the active grab. If any of the pre-passive copies of the event is returned with the flag MRF_PREVENT_PASS_THROUGH, the active event will not be sent to its destination. You can use this feature to set up input filters, having an object receive all mouse events pre-passive and filtering out those that should not be delivered. The message
MSG_VIS_REMOVE_BUTTON_PRE_PASSIVE
removes any pre-passive mouse grab from the object.
A post-passive mouse grab is similar to a pre-passive except that the post-passive object receives the event
after
it is sent to its normal destination. The post-passive object will receive a
MSG_META_POST_PASSIVE_...
with the same flags and position information as sent with the input event. An object that has the post-passive grab can release it by sending itself a
MSG_VIS_REMOVE_BUTTON_POST_PASSIVE
.
void MSG_VIS_ADD_BUTTON_PRE_PASSIVE();
A visible object sends itself this message (with
@call
) when it wants to gain a pre-passive mouse grab. The object will receive all subsequent mouse events in the form of
MSG_META_PRE_PASSIVE_...
before
the event's destination object receives them; this message will carry the same input information as passed with the input event. The object should handle
MSG_META_PRE_PASSIVE_...
and, if the event is not to be sent normally to its destination, should return the flag MRF_PREVENT_PASS_THROUGH from that handler. The pre-passive grab will be released when the object sends itself a
MSG_VIS_REMOVE_BUTTON_PRE_PASSIVE
.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself when it wants to gain a pre-passive mouse grab.
Interception: Unlikely--Note that the object must, however, intercept any
MSG_META_PRE_PASSIVE...
events it is interested in.
void MSG_VIS_REMOVE_BUTTON_PRE_PASSIVE();
This message removes the pre-passive grab from a visible object.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself when it has a pre-passive grab and wants to release it.
Interception: Unlikely.
void MSG_VIS_ADD_BUTTON_POST_PASSIVE();
A visible object sends itself this message (with
@call
) when it wants to gain the post-passive mouse grab. The object will receive all subsequent mouse events in the form of
MSG_META_POST_PASSIVE_...
after
the event's destination object receives them; this message will carry the same input information as passed with the input event. The object should handle the appropriate
MSG_META_POST_PASSIVE_...
to properly receive the events. The post-passive grab will be released when the object receives a
MSG_VIS_REMOVE_BUTTON_POST_PASSIVE
.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself when it wants to receive post-passive input events.
Interception: Unlikely--Note that the object must, however, handle any
MSG_META_POST_PASSIVE_...
events it is interested in.
void MSG_VIS_REMOVE_BUTTON_POST_PASSIVE();
This message removes any post-passive mouse grab from the object.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself to release a post-passive mouse grab.
Interception: Unlikely.
MSG_VIS_TAKE_GADGET_EXCL, MSG_VIS_RELEASE_GADGET_EXCL, MSG_VIS_LOST_GADGET_EXCL, MSG_VIS_VUP_QUERY_FOCUS_EXCL, MSG_VIS_FUP_QUERY_FOCUS_EXCL, MSG_VIS_VUP_ALLOW_GLOBAL_TRANSFER
The gadget exclusive is a marker in the system used by the UI to indicate which object has exclusive access to input gadget functionality. Only one gadget at a time may have the gadget exclusive, and the gadget exclusive may be forcibly taken from an object by another object (for example, when a system-modal dialog comes up during a drag operation).
At times, an object will force the mouse input to go to a different object from that which has the current active grab. This is done almost exclusively by the Specific UI library and is rarely, if ever, done by applications. Three messages can be used in determining which object has the current "gadget exclusive," or active mouse grab. These are shown below.
In addition, individual objects can get information about the current state of the Focus hierarchy with
MSG_VIS_VUP_QUERY_FOCUS_EXCL
and
MSG_VIS_FUP_QUERY_FOCUS_EXCL
, also shown below.
To deal with a quick-transfer operation, a visible object may also have to use the message
MSG_VIS_VUP_ALLOW_GLOBAL_TRANSFER
. This message may be used to remove the mouse grab from the GenView in which the visible object resides, thereby allowing mouse events to reach other objects outside the view window.
void MSG_VIS_TAKE_GADGET_EXCL(
optr child);
This message causes the passed object to be given the gadget exclusive. Any object currently having the gadget exclusive will subsequently receive a
MSG_VIS_LOST_GADGET_EXCL
. This is used primarily by the Specific UI.
Source: Unrestricted. Typically sent by a visible object that will next grab the mouse.
Destination: Any visible object--normally sent by an object to its visible parent.
Parameters:
child
The optr of the object to which the gadget exclusive will be given (normally the calling object).
Return: Nothing.
Interception: Unlikely.
See Also:
MSG_VIS_GRAB_MOUSE
,
MSG_VIS_LOST_GADGET_EXCL
void MSG_VIS_RELEASE_GADGET_EXCL(
optr child);
This message causes the passed object to release the gadget exclusive. The object specified by
child
will then receive a
MSG_VIS_LOST_GADGET_EXCL
.
Source: Unrestricted. Typically sent by an object that has a mouse grab and expects to release it.
Destination: Any visible object--normally sent by the object to it's parent.
Parameters:
child
The optr of the object which is to lose the gadget exclusive (normally the calling object).
Return: Nothing.
Interception: Unlikely.
See Also:
MSG_VIS_RELEASE_MOUSE
,
MSG_VIS_LOST_GADGET_EXCL
void MSG_VIS_LOST_GADGET_EXCL();
This message, when received, indicates that the recipient has lost its hold on the gadget exclusive. When an object receives this, it should release the active mouse grab, if appropriate.
Source: Unrestricted--typically sent by the UI.
Destination: The visible object losing the gadget exclusive.
Interception: Mouse grabs should be released in this handler.
void MSG_VIS_VUP_QUERY_FOCUS_EXCL(
ObjectAndGrabParams *retValue);
This message queries up the visible hierarchy to find the object having the current focus in the current window. The current window is taken to be the window in which the object receiving the message resides.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself to find the focus optr in its window.
Parameters:
retValue
A pointer to an empty
ObjectAndGrabParams
structure, shown below.
Return: The
ObjectAndGrabParams
structure pointed to by
retVal
will be filled with the appropriate data.
Interception: Unlikely.
Structures:
The structure of the
ObjectAndGrabParams
is shown below:
typedef struct {
word OAGP_grabFlags; /* flags */
word OAGP_unused; /* reserved */
optr OAGP_object; /* object with focus */
} ObjectAndGrabParams;
The
OAGP_grabFlags
field contains a record of
HierarchicalGrabFlags
OAGP_object
has the exclusive.void MSG_VIS_FUP_QUERY_FOCUS_EXCL(
ObjectAndGrabParams *retValue);
This message queries the focus hierarchy to see which object has the current focus. The current focus object does not have to be in the caller's visible tree.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
retValue
A pointer to an empty
ObjectAndGrabParams
structure, shown above in the entry for
MSG_VIS_VUP_QUERY_FOCUS_EXCL
.
Return: The
ObjectAndGrabParams
structure pointed to by
retVal
will be filled with the appropriate data.
Interception: Unlikely. This message is not deliverd to all visible objects, rather only those marked as VTF_WIN_GROUP or VTF_IS_INPUT_NODE. If you are implementing a new focus node, and need this message, and are not a window group, you will need to set the VTF_IS_INPUT_NODE bit in your init routine.
Structures: The structure of the
ObjectAndGrabParams
is shown in the entry for
MSG_VIS_VUP_QUERY_FOCUS_EXCL
.
void MSG_VIS_VUP_ALLOW_GLOBAL_TRANSFER();
This message is sent by a visible object to itself when a quick-transfer operation is underway and the pointer has to be allowed to leave the bounds of the object's view window. This message will travel up to the content object, which will indicate to the GenView that the pointer events must be allowed to go to other windows in the system.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself when the global transfer must be allowed outside its window.
Interception: Unlikely.
MSG_VIS_VUP_SET_MOUSE_INTERACTION_BOUNDS, MSG_VIS_VUP_GET_MOUSE_STATUS, MSG_VIS_VUP_TERMINATE_ACTIVE_MOUSE_FUNCTION, MSG_VIS_VUP_BUMP_MOUSE
The UI can control the mouse image and events as they occur. Because the UI is based on the visible classes, the messages that control the mouse status are also available to you, though they will probably be of very little utility. These messages are given below.
void MSG_VIS_VUP_SET_MOUSE_INTERACTION_BOUNDS(@stack
int bottom,
int right,
int top,
int left);
A visible object requesting the mouse grab sends this message up the visible tree. This message will be handled by a content object. It indicates a new set of draggable bounds in case the user initiates a drag-scrolling operation. This message is sent automatically when the visible object requests the grab.
Source: A visible object requesting a mouse grab.
Destination: The sender sends this message to itself.
Parameters:
bottom, right, top, left
The four bounds of the new bounding rectangle. Default is the bounds of the object sending the message.
Return: Nothing.
Interception: Unlikely.
word MSG_VIS_VUP_GET_MOUSE_STATUS();
This message is rarely used by any objects outside the UI library. It returns the information passed with the last mouse event. The word return value contains two byte-sized sets of flags. The high byte is a list of the active UI functions, and the low byte represents the current button information.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself when it can not locally store the latest mouse information.
Parameters: None.
Return: A word containing two values: The high word is a record of type
UIFunctionsActive
, and the low word is a word of
ButtonInfo
.
Interception: Unlikely.
void MSG_VIS_VUP_TERMINATE_ACTIVE_MOUSE_FUNCTION();
This message is sent by a visible object to itself to terminate any active mouse function, forcing it to be a function of type "other." This message is used only by the Specific UI library in cases where input synchronization problems occur in specific places. Applications should generally not use this message.
Source: A visible object handling active input events.
Destination: Sent by the visible object to itself.
Interception: This message should not be subclassed.
void MSG_VIS_VUP_BUMP_MOUSE(
int xBump,
int yBump);
This message causes the UI to bump the pointer image on the screen by the passed offsets as if the user had moved the mouse. It's unlikely your objects will subclass this message; you may, however, use it to bump the mouse. It is most often used by specific UI objects (menus, scrollers) that make the mouse follow their movements.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
xBump
The horizontal amount to bump the mouse.
yBump
Return: Nothing.
Interception: Unlikely.
MSG_META_GRAB_KBD, MSG_META_FORCE_GRAB_KBD, MSG_META_RELEASE_KBD
The keyboard, like the mouse, may be grabbed by visible objects. Keyboard events arrive in the form
MSG_META_KBD_CHAR
; a single message represents all different types of keyboard events (unlike mouse events, which can be much more diverse).
To grab the keyboard, the visible object should send itself the message
MSG_META_GRAB_KBD
. If the grab should be made in any circumstances, the object should use
MSG_META_FORCE_GRAB_KBD
. To release the keyboard grab, the object should send itself
MSG_META_RELEASE_KBD
.
void MSG_META_GRAB_KBD();
A visible object will send itself this message (using
@call
) when it wants to gain the keyboard grab. To release the grab, it must send itself a
MSG_META_RELEASE_KBD
. If it wants to gain the exclusive regardless of whether another object has it, it should use
MSG_META_FORCE_GRAB_KBD
.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself to gain the keyboard grab.
Interception: Unlikely--Note that the object must, however, intercept
MSG_META_KBD_CHAR
to receive the subsequent keyboard events.
void MSG_META_FORCE_GRAB_KBD();
A visible object will send itself this message (using
@call
) when it wants to gain the keyboard grab whether or not another object currently has it. To release the grab, the object must later send itself
MSG_META_RELEASE_KBD
.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself to force a keyboard grab.
Interception: Unlikely.
void MSG_META_RELEASE_KBD();
A visible object that has the keyboard grab must send itself this message to release the grab.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself to release its keyboard grab.
Interception: Unlikely.
MSG_VIS_QUERY_IF_OBJECT_HANDLES_INK
If a visible object expects and wants Ink input, it should subclass the message
MSG_VIS_QUERY_IF_OBJECT_HANDLES_INK
. This message queries the visible object, which should return specific values based on the current input state and object bounds.
This message has two default handlers; the default
VisClass
handler always returns
false
, indicating that the visible object does not expect Ink input. You can, however, substitute a second default handler for the
VisClass
handler by adding the following line to your Goc file after the object's class definition:
@method VisObjectHandlesInkReply, <YourClass>,
MSG_VIS_QUERY_IF_OBJECT_HANDLES_INK;
This will, in essence, substitute the system-provided routine
VisObjectHandlesInkReply()
for a subclassed message handler. This routine will do the right thing for the object in interacting with the input manager. All subsequent input events will be considered Ink events.
void MSG_VIS_QUERY_IF_OBJECT_HANDLES_INK(
VisCallChildrenInBoundsFrame *data);
This message is subclassed by objects that handle Ink input. See above for directions on handling this message. The parameters are five data words that may be modified and the bounds of a rectangle. This message will be sent to all objects whose bounds fall within the passed rectangle.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
data
A pointer to a
VisCallChildrenInBoundsFrame
structure containing the bounding rectangle and five words of data. This structure is described below.
Return: Three fields of the
VisCallChildrenInBoundsFrame
structure pointed to by
data
will have meaning on return. See the Interception paragraph below to determine whether the return values should be set or not in a subclassed handler.
VCCIBF_data1
VCCIBF_data2
VCCIBF_data3
Interception: If an object wants to receive ink messages, it should do the following things in its handler for this message: First compare the passed
VCCIBF_data3
value with the top bound of the object. Then, if the upper bound of the object is less than the
VCCIBF_data3
value (or if the value in
VCCIBF_data1
is zero), then the object should return the values indicated in the Return paragraph above. Otherwise, if these conditions are not met, it should return with the structures and registers unchanged.
Structures: The
VisCallChildrenInBoundsFrame
structure is shown below:
typedef struct {
word VCCIBF_data1;
word VCCIBF_data2;
word VCCIBF_data3;
word VCCIBF_data4;
word VCCIBF_data5;
/* Five data words as described above */
Rectangle VCCIBF_bounds;
/* bounds must be in the coordinate
* system of the parent of the caller */
} VisCallChildrenInBoundsFrame;
Visible objects can not be used unless they are placed within object trees. The top object of the tree must be of a subclass of
VisContentClass
. Other objects in the tree can be of any visible object class. Keep in mind, however, that
VisClass
objects can not have children; only the composite classes (
VisCompClass
and
VisContentClass
) may have children. Therefore,
VisClass
is useful only for leaf objects.
Each visible object has a
VI_link
instance field. This field specifies the optr of that object's next sibling in the tree. Since this is a field of
VisClass
, both composites and noncomposites have it. Composite objects also have a
VCI_comp
field which contains the optr of the composite's first child. Thus, visible trees use the same format as normal object trees.
Getting Visible Tree Information
Sending Messages Through the Tree
Visible Object Window Operations
MSG_VIS_DESTROY
Visible objects are just like any other objects in the ways they are created and destroyed. You can create visible objects in many ways; the easiest is to set them up in a resource and simply load or duplicate the resource block at run-time. You can also use the
ObjInstantiate()
routine to instantiate new visible objects on the fly from your predefined subclass of
VisClass
,
VisCompClass
, or
VisContentClass
. the GEOS Programming chapter details how to instantiate a new object of a given class.
Destroying visible objects is very simple. You only need to use the message
MSG_VIS_DESTROY
, which works on a visible object and all its children (if it has any). This message removes the visible branch from the screen if necessary, detaches the visible objects from the visible tree, and then destroys the object (freeing its instance chunk). The only thing the object must do is clean up after itself--in its
MSG_META_DETACH
or
MSG_META_FINAL_OBJ_FREE
handler, it should free any memory that it allocated explicitly for its own use, for example.
MSG_VIS_DESTROY
also marks the destroyed object's parent invalid both in geometry and image so the tree will be updated properly.
void MSG_VIS_DESTROY(
VisUpdateMode updateMode);
This message is the high level routine for destroying branches of visible trees. This message will close and destroy the entire branch, unlinking any visible objects in the branch under the recipient object. The parent of the removed branch will be marked invalid for later visual update. This message may be subclassed to replace the geometry update handling, but this is not easily done and is rare.
Source: Unrestricted.
Destination: Any visible object (or head of a visible branch).
Parameters:
updateMode
A
VisUpdateMode
that determines when the visible parent of the destroyed object/branch will be updated on the screen.
Return: Nothing.
Interception: Unlikely--may be subclassed if the parent is not to be marked invalid. This is extremely rare.
MSG_VIS_ADD_CHILD, MSG_VIS_REMOVE, MSG_VIS_REMOVE_CHILD, MSG_VIS_MOVE_CHILD, MSG_VIS_ADD_NON_DISCARDABLE_VM_CHILD, MSG_VIS_REMOVE_NON_DISCARDABLE_VM_CHILD, MSG_VIS_REMOVE_NON_DISCARDABLE
Once you have objects instantiated, you can connect them together into an object tree. If you know the structure of your tree beforehand, you can create the tree explicitly in your .goc file, just as you would create your generic object tree.
For many purposes, however, a dynamic object tree is much more useful. To use it, you must be able to add and remove objects easily as well as move them within the tree easily.
To add an object to a branch of a visible tree, use the message
MSG_VIS_ADD_CHILD
. This message adds a visible object as the child of a composite; if the new child is a composite with its own children, the entire branch is added to the tree. You can add a child at any position in the composite's child list (e.g., as the first child, as the second child, as the last child, etc.), and you can mark the child dirty after addition if you want.
For example, if you have a composite visible object with two children that is currently unattached to any visible tree, you can attach it to a tree with
MSG_VIS_ADD_CHILD
. The figure above shows this process and the line of code used to add the composite as the second child of an object in the tree.
Note that the child in the example is added as child one. The child list of a composite is zero-based, so the first child is referred to as number zero, the second is number one, and so on. The last child may always be referred to as CCO_LAST; likewise, the first child may always be referred to as CCO_FIRST.
To remove an object or branch from a visible tree, you can use either
MSG_VIS_REMOVE
or
MSG_VIS_REMOVE_CHILD
.
MSG_VIS_DESTROY
may also be used, but only if the entire branch should be destroyed after being removed from the tree. Both
MSG_VIS_REMOVE
and
MSG_VIS_REMOVE_CHILD
detach the object from the visible tree and visually update the parent immediately.
MSG_VIS_REMOVE
, however, should be sent directly to the object being removed, while
MSG_VIS_REMOVE_CHILD
is sent to the parent of the object being removed. When removing a child from its parent, you can specify the child by position number (e.g., remove the last child or the first child).
You can move a child within its child list with
MSG_VIS_MOVE_CHILD
. This message is sent to the parent and simply moves the child within the parent's child list. To move a child from one parent to another, you must first remove it and then add it to the other parent with
MSG_VIS_REMOVE_CHILD
and
MSG_VIS_ADD_CHILD
. This message, as the others, will move the child's entire branch with it.
In many cases, you may save visible objects directly to VM documents using GenDocument objects and the document controllers. In cases like this, the objects you save to the file must not be discarded by the UI if the visible object is taken off the tree or removed. These objects are known as "non-discardable" visible objects stored in a VM file, and unless they're handled specially, they can cause your documents to crash your application.
Any top-level object you save directly to a file must be treated as non-discardable. That is, any object that gets dynamically added to or removed from a visible tree (such as a vis object that gets added as the child of a GenDocument when the document is opened) must be added, removed, and managed as a non-discardable object. There are three messages that deal specifically with non-discardable visible objects; these are detailed below and are
MSG_VIS_ADD_NON_DISCARDABLE_VM_CHILD
,
MSG_VIS_REMOVE_NON_DISCARDABLE_VM_CHILD
, and
MSG_VIS_REMOVE_NON_DISCARDABLE
.
void MSG_VIS_ADD_CHILD(
optr child,
CompChildFlags flags);
This message attaches the passed object as a child of the composite handling the message. If the parent is already opened and on the screen, you must invalidate the child with
MSG_VIS_MARK_INVALID
, passing the invalidation VOF_WINDOW_INVALID; the composite and child will be updated appropriately according to the
VisUpdateMode
passed with the invalidation. If, however, the parent is not opened, the child will automatically be opened when the parent is opened.
Source: Unrestricted.
Destination: Any visible composite object.
Parameters:
child
The optr of the visible object to be added as a child.
flags
CompChildFlags
, described below.Return: Nothing.
Interception: You should not subclass this message.
Structures: The
CompChildFlags
structure contains one one-bit flag and one 15-bit unsigned numerical field. These are described below and can be found in
metaC.goh
.
typedef WordFlags CompChildFlags; #define CCF_MARK_DIRTY 0x8000 #define CCF_REFERENCE 0x7fff
#define CCO_FIRST 0x0000 #define CCO_LAST 0x7FFF
#define CCF_REFERENCE_OFFSET 0
Warnings: Do not pass the optr of an object that is already the child of another object. The results are unpredictable and will likely result in an error.
void MSG_VIS_REMOVE(
VisUpdateMode updateMode);
This is the high-level message that closes (if necessary) and removes a visible branch from the object tree. The parent of the branch is marked invalid for visual update according to the passed
VisUpdateMode
.
Unlike
MSG_VIS_DESTROY
, this message does not destroy the visible branch but only unlinks it from the tree. This message may not be subclassed by any object. This message is useful for hiding visible branches which may be added again later with
MSG_VIS_ADD_CHILD
.
Source: Unrestricted.
Destination: Any visible composite object.
Parameters:
updateMode
The
VisUpdateMode
used to update the composite from which the child is removed. VUM_MANUAL is not allowed.
Return: Nothing.
Interception: Do not subclass this message.
Warnings: This message will not allow VUM_MANUAL to be passed as the
updateMode
.
void MSG_VIS_REMOVE_CHILD(
optr child,
CompChildFlags flags);
This message removes the specified child from the object tree. This message should be rarely used and used with care; it does not close the visible branch but simply removes it. Consider using the higher-level
MSG_VIS_REMOVE
instead. Note that all grabs (focus, gadget, mouse, etc.) must be released by the child and all its children before the branch can be removed safely.
Source: Unrestricted.
Destination: The parent composite of the passed object.
Parameters:
child
The optr of the child to be removed. If this optr is not among the recipient's children, an error will likely occur.
flags
CompChildFlags
as described in
MSG_VIS_ADD_CHILD
on typedef WordFlags CompChildFlags; #define CCF_MARK_DIRTY 0x8000 #define CCF_REFERENCE 0x7fff
.Return: Nothing.
Interception: You should not subclass this message.
Warnings: Most likely you should use
MSG_VIS_REMOVE
instead of this message.
MSG_VIS_REMOVE
takes care of extra bookkeeping automatically that can be difficult.
void MSG_VIS_MOVE_CHILD(
optr child,
CompChildFlags flags);
This message moves a child of the recipient to another location among its siblings. It essentially removes the child from the branch and then re-adds it in the same manner as
MSG_VIS_ADD_CHILD
. This message does
not
move the child from one parent to another; you must use a combination of
MSG_VIS_REMOVE
and
MSG_VIS_ADD_CHILD
to achieve that.
Source: Unrestricted.
Destination: The parent composite of the passed object.
Parameters:
child
The optr of the child to be removed. If this optr is not among the recipient's children, an error will likely occur.
flags
CompChildFlags
as described in
MSG_VIS_ADD_CHILD
on typedef WordFlags CompChildFlags; #define CCF_MARK_DIRTY 0x8000 #define CCF_REFERENCE 0x7fff
.Return: Nothing.
Interception: You should not subclass this message.
void MSG_VIS_ADD_NON_DISCARDABLE_VM_CHILD(
optr child,
CompChildFlags flags);
This message performs exactly the same as
MSG_VIS_ADD_CHILD
except that it also increments the object's in-use count so it will never be discarded. This is used on top objects in visible sub-trees that are saved to document files: The object is added as a non-discardable file when the document is opened, and it is removed as a non-discardable child (with
MSG_VIS_REMOVE_NON_DISCARDABLE_VM_CHILD
or
MSG_VIS_REMOVE_NON_DISCARDABLE
) when the document is closed.
Source: Unrestricted--typically a document object when opening the file.
Destination: The new parent of the visible object being added to the tree.
Parameters:
child
The optr of the new child being added to the tree.
flags
CompChildFlags
indicating where the child should be added. CCF_MARK_DIRTY is ignored in this record.Return: Nothing.
Interception: Generally not intercepted.
void MSG_VIS_REMOVE_NON_DISCARDABLE_VM_CHILD(
optr child);
This message performs exactly the same as
MSG_VIS_REMOVE_CHILD
except that it is used with
MSG_VIS_ADD_NON_DISCARDABLE_VM_CHILD
rather than with
MSG_VIS_ADD_CHILD
. This message decrements the in-use count before removing the child, thereby undoing the extra increment performed by
MSG_VIS_ADD_NON_DISCARDABLE_VM_CHILD
.
Source: Unrestricted--typically a document object when closing the file.
Destination: The parent of the visible object being removed from the tree.
Parameters:
child
The optr of the child being removed.
Return: Nothing.
Interception: Generally not intercepted.
void MSG_VIS_REMOVE_NON_DISCARDABLE(
VisUpdateMode updateMode)
This message performs exactly the same as MSG_VIS_REMOVE except that it decrements the object's in-use count before removing it. This message should therefore be used in conjunction with the adding message MSG_VIS_ADD_NON_DISCARDABLE_VM_CHILD and should not be used with MSG_VIS_ADD_CHILD. Likewise, MSG_VIS_REMOVE should not be used with this MSG_VIS_ADD_NON_DISCARDABLE_VM_CHILD.
Source: Unrestricted--typically a document object when closing the file.
Destination: The visible object being removed from the tree.
Parameters:
updateMode
A
VisUpdateMode
value indicating when the object should be visibly removed from the tree. VUM_MANUAL is not allowed.
Return: Nothing.
Interception: Generally not intercepted.
MSG_VIS_FIND_CHILD, MSG_VIS_FIND_CHILD_AT_POSITION, MSG_VIS_COUNT_CHILDREN, MSG_VIS_FIND_PARENT
When an application manages a visible object tree, it will most likely need to find children, count children, or get the optr of a particular object in the tree.
VisClass
offers four messages to provide this bookkeeping information. These four messages are listed below.
word MSG_VIS_FIND_CHILD(
optr object);
This message returns the zero-based position of the specified child among the parent's children.
Source: Unrestricted.
Destination: Any visible composite object.
Parameters:
object
The optr of the child to be found.
Return: The zero-based position of the child in the parent's child list. (E.g., the first child returns zero, the second child returns one, the third child returns two, etc.) If
object
is not the optr of one of the composite's children, the value -1 will be returned. If sent to a non-composite object, the message will also return -1.
Interception: Unlikely.
optr MSG_VIS_FIND_CHILD_AT_POSITION(
word position);
This message returns the optr of the child occupying the
position
specified among the recipient's children.
Source: Unrestricted.
Destination: Any visible composite object.
Parameters:
position
The zero-based position of the child whose optr is to be returned.
Return: The optr of the child occupying the passed
position
. If no child occupies that position, or if the message is sent to a non-composite object, the retuned value will be NullOptr.
Interception: Unlikely.
word MSG_VIS_COUNT_CHILDREN();
This message returns the number of children the recipient object has. The count is not zero-based; if a composite has five children, this message will return five.
Source: Unrestricted.
Destination: Any visible composite object.
Parameters: None.
Return: The number of children the object has. If the object has no children (includes non-composite objects), the return will be zero.
Interception: Unlikely.
optr MSG_VIS_FIND_PARENT();
This message returns the optr of the recipient's parent composite.
Source: Unrestricted.
Destination: Any visible composite object.
Parameters: None.
Return: The optr of the object's parent composite. If the message is sent to the top node of a visible tree, the return value will be NullOptr.
Interception: Unlikely.
Tips: If you want to send a message to your parent, use the
@visParent
macro defined in the next section.
Often an object will need to contact its parent or children but will not know their precise optrs. Other times, you may need to send a message to a particular object in the tree but don't know where in the tree the object is. GEOS provides several ways to dispatch messages to parents and children and even to objects of a given class.
@visParent, @visChildren, MSG_VIS_CALL_PARENT, MSG_VIS_SEND_TO_PARENT, MSG_VIS_SEND_TO_CHILDREN
To send a given message to an object's parent (to check valid bounds, to check the parent's state, etc.), you can use the macro
@visParent
. To do this, substitute the macro in place of the destination object's name, as follows:
kids = @call @visParent::MSG_VIS_COUNT_CHILDREN();
The above call is more efficient than using two message calls for the same thing, as follows:
myParent = @call self::MSG_VIS_FIND_PARENT(); kids = @call myParent::MSG_VIS_COUNT_CHILDREN();
Note that either
@call
or
@send
may be used with the
@visParent
macro.
A similar macro,
@visChildren
, is offered for sending messages to a composite's children. Note, however, that you can only use the
@send
keyword to send messages with this macro; there is no way for a single call to collect return values from many different objects. So, if you need to pass pointers to your children, you will have to get each child's optr in turn and dispatch the message to it individually. (Recall that pointers should not be passed with
@send
because they may be invalidated by the time the message is handled.) The format for using the
@visChildren
macro is as follows:
@send @visChildren::MSG_VIS_INVALIDATE();
This usage is much more efficient than counting the composite's children and using a loop to get the child's optr and send the child the message.
In addition to providing the above macros,
VisClass
lets you pass recorded events to a visible object's parent or children. This can be useful, for example, if you need to send a message to another object's parent; you might otherwise first have to find the optr of the object's parent and then send the message directly. Instead, you can use the
VisClass
messages
MSG_VIS_CALL_PARENT
and
MSG_VIS_SEND_TO_PARENT
to pass recorded (encapsulated) events to the recipient's parent.
To send a recorded event to a visible object's children use the message
MSG_VIS_SEND_TO_CHILDREN
. The recorded event will not be allowed to return anything for the same reason the
@visChildren
macro can not.
void MSG_VIS_CALL_PARENT(
EventHandle event);
This message delivers the passed recorded event to the parent of the recipient object. It acts as a call, executing immediately even across threads.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
event
The event handle of the prerecorded event to be delivered.
Return: Nothing.
Interception: Unlikely.
Tips: In Goc, an object should not send this message to itself; instead, it should use the
@visParent
macro described above.
void MSG_VIS_SEND_TO_PARENT(
EventHandle event);
This message delivers the passed recorded event to the parent of the recipient object. It acts as a send, allowing the caller to continue execution without waiting for the event to be handled.
Source: Unrestricted.
Destination: Any visible object.
Parameters:
event
The event handle of the recorded event to be delivered.
Return: Nothing.
Interception: Unlikely.
Tips: In Goc, an object should not send this message to itself; instead, it should use the
@visParent
macro described above.
void MSG_VIS_SEND_TO_CHILDREN(
EventHandle event);
This message delivers the passed recorded event to each of the recipient's children. It acts as a message send and can not return values; there is no way for a single message to call several objects and return values from each with a single call.
Source: Unrestricted.
Destination: Any visible composite object.
Parameters:
event
The event handle of the recorded event to be delivered.
Return: Nothing.
Structures: In Goc, an object should not send this message to itself; instead, it should use the
@visChildren
macro described above.
Warnings: Do not pass pointers in the recorded event's parameters because the message may not be handled before the pointers are invalidated.
MSG_VIS_VUP_FIND_OBJECT_OF_CLASS, MSG_VIS_VUP_CALL_OBJECT_OF_CLASS, MSG_VIS_VUP_SEND_TO_OBJECT_OF_CLASS, MSG_VIS_VUP_TEST_FOR_OBJECT_OF_CLASS
VisClass
has several messages that automatically travel up the visible object tree until they get to an object that meets the proper criteria; they then deliver themselves to that object. This is accomplished by the default handler in
VisClass
recognizing whether the given object meets the criteria; if it does not, the handler passes the message up to the object's parent.
To find an object of a given class in the tree, use the message
MSG_VIS_VUP_FIND_OBJECT_OF_CLASS
. This message travels up the tree starting at the recipient until it reaches the first object of that class. So if you are looking for an object of
VisCompClass
, at the most the message will be passed up a single level.
If you need to send a message to an object of a given class in the visible tree, you can either find it and send it the message or send the message directly with the visible upward messages
MSG_VIS_VUP_CALL_OBJECT_OF_CLASS
and
MSG_VIS_VUP_SEND_TO_OBJECT_OF_CLASS
. These messages search up the tree in the same was as
MSG_VIS_VUP_FIND_OBJECT_OF_CLASS
, and they then deliver the passed event to the resulting object.
To see simply whether an object of a given class exists in the visible tree, use
MSG_VIS_VUP_TEST_FOR_OBJECT_OF_CLASS
. This is useful if you are going to use
MSG_VIS_VUP_CALL_OBJECT_OF_CLASS
(or its counterpart). If no object of the given class exists, you can skip sending the recorded message.
To send classed messages to an object in the tree that is of a specific class, you can use
TravelOption
with certain
MetaClass
messages.
VisClass
defines a travel option
TO_VIS_PARENT, which sends the message to the first object up the tree that is of the specified class.
optr MSG_VIS_VUP_FIND_OBJECT_OF_CLASS(
ClassStruct *class);
This message searches up the visible object tree until it encounters an object of the specified class. It then returns the optr of that object.
Source: Unrestricted.
Destination: Any visible object--typically sent by a visible object to itself to find an object of the given class above it in the visible object tree.
Parameters:
class
A pointer to the
ClassStruct
structure of the class to be searched for.
Return: The optr of the object of the passed class. If multiple objects of this class exist in the tree, the first encountered will be returned. If no objects of this class are in the tree, a NullOptr will be returned.
Interception: Unlikely--only objects that masquerade as objects of a different class would subclass this message. This practice is highly discouraged.
Boolean MSG_VIS_VUP_TEST_FOR_OBJECT_OF_CLASS(
ClassStruct *class);
This message searches up the visible tree and determines whether an object of the given class is in the tree.
Source: Unrestricted.
Destination: Any visible object--typically sent before
MSG_VIS_VUP_CALL_OBJECT_OF_CLASS
or
MSG_VIS_VUP_SEND_TO_OBJECT_OF_CLASS
to ensure that a recipient for the message exists.
Parameters:
class
A pointer to the
ClassStruct
structure of the class to be searched for.
Return:
True
if the class is found;
false
if it is not.
Interception: Unlikely.
void MSG_VIS_VUP_CALL_OBJECT_OF_CLASS(
EventHandle event);
This message searches up the visible tree until it encounters an object of the proper class for the recorded event. The class is specified within the passed
event
. When the first such object is found, it will be called with the classed event as if an
@call
had been used with the event directly.
Source: Unrestricted.
Destination: Any visible object--The passed event will be delivered to the first object of the appropriate class, not necessarily to the recipient of the
MSG_VIS_VUP_CALL_OBJECT_OF_CLASS
.
Parameters:
event
The event handle of a recorded event.
Return: The classed event delivered by this message may return values as determined by the event. This message returns nothing.
Interception: Unlikely.
void MSG_VIS_VUP_SEND_TO_OBJECT_OF_CLASS(
EventHandle event);
This message searches up the visible tree until it encounters an object of the proper class for the recorded event. The class is specified within the passed
event
. When the first such object is found, the message will be delivered to that object as if an
@send
had been used with the event directly.
Source: Unrestricted.
Destination: Any visible object--The passed event will be delivered to the first object of the appropriate class, not necessarily to the object that received the
MSG_VIS_VUP_SEND_TO_OBJECT_OF_CLASS
.
Parameters:
event
The event handle of a recorded event.
Return: Nothing. The recorded event may not return anything.
Interception: Unlikely.
Warnings: The recorded event should not pass pointers among its parameters.
MSG_VIS_VUP_QUERY
You can create your own messages that get passed up the visible tree by creating aliases of
MSG_VIS_VUP_QUERY
.
MSG_VIS_VUP_QUERY
, by itself, does nothing useful; it simply gets passed up the visible tree without ever being handled.
You can create your own visible queries to return different types of values from objects higher up in the object tree. Take, for example, a music-teaching application which uses note objects as distant children of a sheet music object. If the note objects needed to know what key they were supposed to be in, they would query up the tree with a special upward query message. If we assume the sheet music object kept this information, it would want to respond to the query message with the appropriate value. Thus, the sheet music class would have a line similar to the following:
@alias(MSG_VIS_VUP_QUERY)
MusicKeyType MSG_VIS_VUP_QUERY_MUSIC_KEY();
This line creates an alias for the general-purpose upward query. The sheet music object should have a handler for
MSG_VIS_VUP_QUERY_MUSIC_KEY
in which it figures out and returns the appropriate key. This type of upward query can be invaluable in many different situations.
void MSG_VIS_VUP_QUERY();
This message simply queries up the tree until it is handled. It is extensible so visible objects can implement their own upward queries without adding handlers to every class in between it and the query handler.
It is extremely rare that any object would send or handle
MSG_VIS_VUP_QUERY
on its own; many classes, however, may alias this message and create their own versions of the upward query.
Source: Unrestricted--see note above.
Destination: Any visible object--see note above. Typically sent by a visible object either to itself or directly to its visible parent.
Parameters: None--an alias of this message may have parameters.
Return: Nothing--an alias of this message may have return values.
Interception:
MSG_VIS_VUP_QUERY
itself should not be intercepted. Its aliases, however, should be intercepted by the appropriate classes that will handle them.
MSG_VIS_VUP_CALL_WIN_GROUP, MSG_VIS_VUP_SEND_TO_WIN_GROUP
VisClass
offers two specific messages for contacting window group objects in a visible tree. These are similar to
MSG_VIS_VUP_CALL_OBJECT_OF_CLASS
and
MSG_VIS_VUP_SEND_TO_OBJECT_OF_CLASS
, except they find the window group of the recipient and deliver the event to the window object. These two messages are detailed below.
void MSG_VIS_VUP_CALL_WIN_GROUP(
EventHandle event);
This message searches up the visible object tree until it encounters a window group object. When the first window group is found, it will be called with the classed event as if an
@call
had been used.
Source: Unrestricted--typically sent by a visible object to itself to deliver the event to its window.
Destination: Any visible object--the passed event will be delivered to a window object, not necessarily to the object that receives the
MSG_VIS_VUP_CALL_WIN_GROUP
.
Parameters:
event
The event handle of a recorded event to be delivered to the window object.
Return: The passed event may return its own values, but
MSG_VIS_VUP_CALL_WIN_GROUP
returns nothing.
Interception: Unlikely.
See Also:
MSG_VIS_VUP_CALL_OBJECT_OF_CLASS.
void MSG_VIS_VUP_SEND_TO_WIN_GROUP(
EventHandle event);
This message searches up the visible object tree until it encounters a window group object. When the first window group is found, the passed event will be delivered to that object as if an
@send
had been used directly.
Source: Unrestricted--typically sent by a visible object to itself to deliver the event to its window.
Destination: Any visible object--the passed event will be delivered to a window object, not necessarily to the object that receives the
MSG_VIS_VUP_CALL_WIN_GROUP
.
Parameters:
event
The event handle of a recorded event to be delivered to the window object.
Return: Nothing. The recorded event may not return values.
Interception: Unlikely.
Warnings: The recorded event may not pass pointers among its parameters.
See Also:
MSG_VIS_VUP_SEND_TO_OBJECT_OF_CLASS.
MSG_VIS_OPEN_WIN, MSG_VIS_CLOSE_WIN, MSG_VIS_WIN_ABOUT_TO_BE_CLOSED, MSG_VIS_MOVE_RESIZE_WIN
Typically, windows will be managed entirely by generic UI objects and the Specific UI library currently in use. You can, however, manage your own
VisClass
-based window objects by using messages normally used only by Specific UI objects. This is a difficult and complex task, however, and it is not recommended. The four messages used for this purpose are detailed below.
void MSG_VIS_OPEN_WIN(
WindowHandle parentWindow);
This message is sent to a window or portal object to open its window. The graphics window will be opened and drawn on the screen, and a visual update will propagate down the displayed visible tree.
Source: Visual update mechanism.
Destination: A window group (VTF_IS_WINDOW) or portal (VTF_IS_PORTAL) object.
Parameters:
parentWindow
The window handle of the open window in which the new window will be created.
Return: Nothing.
Interception: The window group or portal must intercept in order to open the new graphics window and set initial parameters (
VCI_window
).
void MSG_VIS_CLOSE_WIN();
This message is sent to a window or portal object that has its graphics window currently on the screen. The window and its visible branch will be closed (taken off the screen).
Source: Visual update mechanism.
Destination: A window group (VTF_IS_WINDOW) or portal (VTF_IS_PORTAL) object.
Interception: The window group or portal may intercept if more needs to be done than simply closing the graphics window.
void MSG_VIS_WIN_ABOUT_TO_BE_CLOSED();
This message notifies the recipient that the window it's displayed in is about to be closed. The default handler for this will remove the visible branch of the window off the screen so no redraws will occur before the window closes.
Source: Visual update mechanism.
Destination: The window group (VTF_IS_WINDOW) or portal (VTF_IS_PORTAL) object that is being closed; the message will then propagate down the visible tree.
Interception: May be intercepted by either the window group or the VisContent object if the default behavior is not appropriate for the object.
void MSG_VIS_MOVE_RESIZE_WIN();
This message causes the window object to move and/or resize itself based on the bounds of its content object. This message is used only by window or portal objects and is rarely, if ever, used by objects in your applications.
Source: Part of the visual update mechanism--typically called by the window object on itself in its
MSG_VIS_UPDATE_WINDOWS_AND_IMAGE
handler.
Destination: The window group (VTF_IS_WINDOW) or portal (VTF_IS_PORTAL) object to be resized or moved.
Interception: The window object may intercept if it does not want to resize to the bounds of its content object.
MSG_VIS_LAYER_SET_DOC_BOUNDS, MSG_VIS_LAYER_GET_DOC_BOUNDS, MSG_VIS_LAYER_INSERT_OR_DELETE_SPACE
The GEOS graphic space is built on a basis of 16-bit coordinates. A few applications, however, will require much more space for their documents. GEOS also supports the special use of 32-bit coordinates; applications using these coordinates are said to be using the "large document" model.
The visible object library was originally designed with 16-bit coordinates in the default GEOS graphics space. All instance data, message parameters and return values, and coordinates are assumed to be word-sized integers. A large-document visible object library is not provided primarily because there is no single visible model that works well with large coordinates, and also because no single large model works efficiently for all applications.
It is possible, however, for applications to subclass the standard visible classes in order to get them to support the large document model. In order to do this, however, you must understand the basic issues involved with the large model and with using 32-bit coordinates.
As the application developer, you should read the following sections if you will be using the large document model. Each one deals with a different problem facing applications that want large documents.
In addition, some complex applications may offer several different visible layers in the program. For example, a spreadsheet might want to include a graphic object layer for graphics and charts. The content object of the visible tree can be set up to have several different children, each of which is a "layer" that manages its own objects in the window.
The content in charge of the layers must occasionally set and retrieve the document bounds of its children. For example, if the user wants to set the page size of the spreadsheet that has a graphical layer, the content object must set the new size for all its children. To retrieve the current document bounds of a particular object, send it a
MSG_VIS_LAYER_GET_DOC_BOUNDS
. To set the document bounds, send a
MSG_VIS_LAYER_SET_DOC_BOUNDS
. In addition, the application may add or delete space into a layer with
MSG_VIS_LAYER_INSERT_OR_DELETE_SPACE
; for example, if a spreadsheet needs to resize a column, it must send this message to the graphic layer to ensure the layers handle the sizing properly.
void MSG_VIS_LAYER_SET_DOC_BOUNDS(@stack
sdword bottom,
sdword right,
sdword top,
sdword left);
This message sets the 32-bit document bounds for a particular layer object. This message is typically sent by a VisContent object to its children, which are assumed to be layer objects.
Source: Unrestricted--typically sent by a VisContent to its large children.
Destination: Any large (32-bit) visible object or composite.
Parameters:
all
The four parameters describe the new bounds of the large document. Since layer objects typically cover the entire document, the layer object will set its bounds to these values.
Return: Nothing.
Interception: All layer objects and large objects must subclass this message. There is no default handler.
void MSG_VIS_LAYER_GET_DOC_BOUNDS(
RectDWord *bounds);
This message returns the 32-bit document bounds of a particular large visible object. Typically, a VisContent will query its large children with this message when it needs to know their bounds.
Source: Unrestricted--typically sent by a VisContent to its large children.
Destination: Any large (32-bit) visible object or composite.
Parameters:
bounds
A pointer to an empty
RectDWord
structure that describes a set of large bounds.
Return: The pointer to the filled
RectDWord
structure. The structure should, upon return, contain the 32-bit bounds of the large visible object.
Interception: All layer objects and large objects must subclass this message. There is no default handler.
Structures: The
RectDWord
structure is show below for convenience:
typedef struct {
sdword RD_left;
sdword RD_top;
sdword RD_right;
sdword RD_bottom;
} RectDWord;
void MSG_VIS_LAYER_INSERT_OR_DELETE_SPACE(
InsertDeleteSpaceTypes type,
DWFixed spaceY,
DWFixed spaceX,
DWFixed positionY,
DWFixed positionX)
This message should be sent by one layer to another when it changes sizes. An example would be a spreadsheet application with a graphic layer; when a column in the spreadsheet resizes, the graphic layer must resize accordingly.
Source: Any visible layer object.
Destination: The visible layer object requiring resizing.
Parameters:
type
InsertDeleteSpaceType
specifying what sort of operation is taking place.
Return: Nothing.
Interception: This message must be intercepted; it has no default behavior.
The 16-Bit Limit on Visual Bounds
The first issue with large documents is the basic structure of the visible tree. The topmost object of a large visible tree must be able to keep track of information about the current translations and coordinates being used. Typically, the topmost object would be a subclass of
VisContentClass
; this does not change with large trees, though another consideration has to be taken care of.
A content object should not contain any information about the document itself; the content object should not be stored along with other document information. Thus, the object that acts as the content can not be the object that also manages the 32-bit document space. Instead, it is easiest to use a
VisCompClass
object to manage the document space and to place this object as a child of the content.
In addition, you can set up several different composite children of the content, each one managing its own large document space. Each one of these composites is called a "layer object" and manages a "layer" of the document. This way, you can have several different layers (such as a spreadsheet layer and a graphic layer) in the same document. The layer object should manage the calculations and translations necessary for supporting the large document space.
All the GEOS drawing commands are based on 16-bit coordinates. Drawing may only occur within a 16-bit graphics space. The graphics system does, however, support extended translations of the 16-bit graphics space within 32-bit coordinates.
This means that you can think of the large document space as a number of smaller, 16-bit "local" graphics spaces. When you need to draw anything, you first use an extended translation to get near your drawing point in the large document. Then you can draw using 16-bit offsets from the point to which you translated.
The application using the extended translation can do so in two different ways: It can store a 32-bit translation with each visible object, or it can store a 32-bit translation in a visible composite, thereby making the entire visible branch under the composite in a 32-bit graphics space. Visible trees implementing layer objects must use the second option; the layer must contain the translation for the entire visible branch that it manages. If a simple large visible tree does not need layers, it may wish to use the first solution.
The first of the two solutions is simple but takes up additional memory and time; each object, when it draws, must translate the coordinates, draw, then translate back. Two translations for each object could significantly affect drawing performance unless visual updates are handled carefully.
The other solution, storing a translation in the composite object, requires just two translations for the entire branch headed by the composite. Whenever the composite receives
MSG_VIS_DRAW
or
MSG_VIS_VUP_CREATE_GSTATE
, it executes the translation on the GState. As long as the translation is always relative to the GState's current transformation (done using
GrApplyTranslationDWord()
), and as long as the translation is undone before the GState is returned to the caller, drawing will be done properly.
Individual visual objects have 16-bit bounds. If the rules of drawing in the 32-bit graphics space are followed, this is not a problem. Individual objects are constrained to 16-bit width and 16-bit height, however.
The only objects for which having 16-bit bounds is a problem are the tree's content object and all the layer objects. This is because these two types of objects must have width and height greater than 16 bits. This problem is handled differently for each object:
For the content object, the
VI_bounds
field is set to all zeros and is not used. Normally, the content uses its bounds to set the document size in the GenView; the responsibility for setting the GenView's document size then falls to the application.
For the layer object, the
VI_bounds
field is set to all zeros and is not used. If the bounds of the layer object are important to the application, the layer object must be given new instance fields to hold the 32-bit coordinates of the bounds. If not, nothing needs to be done; the bounds can simply be ignored.
In normal-sized visible trees,
MSG_VIS_DRAW
gets sent to all objects in the tree. This draws the entire visible tree, no matter what portions are visible on the screen. For large documents, this can quickly get unwieldy and inefficient.
A better solution is for the layer object of each particular layer to intercept
MSG_VIS_DRAW
and pass it on only to those objects in the affected portion of the document. For this to work, of course, the layer object must know something of the structure and composition of the visible branch below it. This is the primary reason the visible object library does not offer a standard visible layer class--in essence, it must be defined specifically for each application.
Because visible objects and composites maintain their 16-bit bounds in a large document, they can still use the 16-bit geometry manager. Layer objects, however, can not use the geometry manager. All geometry management on the layer level (child positioning, resizing, etc.) must be done by the layer object itself in conjunction with its child composites.
The GenView is built to support large documents, though its default is normal-sized documents. Thus, you can request the view to send large mouse events, which carry with them 32 bits of integer and 16 bits of fraction in each dimension. The visible classes have no default handlers for these messages, so your own classes will have to handle them appropriately.
The large mouse events are the equivalent of their 16-bit counterparts. They just carry different data to represent the coordinates of the pointer. All the mouse events, both large and normal, are described in the Input chapter.
Normal composite objects will not be affected by large mouse events; the composite will continue to send the event on to the proper child as if it were in a 16-bit document. Layer and content objects, however, must process these messages differently.
If no object within the visible tree has the mouse grabbed, the content of the tree must decide which layer object should receive the mouse events. How the content and layer objects negotiate this is up to the particular application; some applications may consider that one layer is "on top of" the others, and other applications may determine which layer is the most appropriate based on the event context. By default, the large mouse events are passed by
VisContentClass
straight on to the first layer child. If you want a more complex scheme, you will have to subclass
VisContentClass
and intercept these messages.
Finally, you should be aware of what attributes to set in both the GenView and the VisContent objects of your visible tree to support the large document. You could easily find this out by looking through the various attributes of those classes (and you are encouraged to do so), but the following guide is provided for convenience:
In the GenView object, set GVA_WINDOW_COORDINATE_MOUSE_EVENTS in the
GVI_attrs
instance data field. This will pass mouse events in terms of offsets from the upper-left corner of the view window rather than in absolute document coordinates.
VisContentClass
handles these events and automatically turns them into document coordinates.
In the VisContent, set VCNA_WINDOW_COORDINATE_MOUSE_EVENTS and VCNA_LARGE_DOCUMENT_MODEL in the
VCNI_attrs
field. The first of these tells the content that it will receive input events in window coordinates rather than in document coordinates. The second will have the effect of making the content object ignore its bounds field and geometry management. It will also tell the content that all its children are layer objects. Setting the large document model will cause the content to send all the following messages on to all its children rather than handle them directly:
MSG_VIS_DRAW
,
MSG_VIS_CONTENT_VIEW_ORIGIN_CHANGED
,
MSG_VIS_CONTENT_VIEW_SCALE_FACTOR_CHANGED
, and
MSG_VIS_CONTENT_VIEW_SIZE_CHANGED
.
You do not have to create all the objects you may need; be aware that the Graphic Object Library provides its own layer object that supports a 32-bit graphic object layer. The spreadsheet object also exports its own layer object.
Layer objects will need to handle
MSG_VIS_LAYER_SET_DOC_BOUNDS
, which will be sent to all layers when the document bounds change.
In essence the layer object's job is to isolate its children and their children from the fact that they are in a 32-bit document rather than a 16-bit document. In order to do this, layer objects must do several things:
MSG_VIS_DRAW
In its handler, the layer should apply any 32-bit translations (using
GrApplyTranslationDWord()
) on the GState provided by
MSG_VIS_DRAW
. It should then intelligently select which of its children are affected by the drawing event and pass the message on to them with the translated GState. The handler should then untranslate the GState before returning.
MSG_VIS_VUP_CREATE_GSTATE
In the handler, the layer must
first
call its superclass (to create the GState normally), then apply the necessary translation using
GrApplyTranslationDWord()
. It can then return the translated GState.Large visible objects in the visible tree should be equipped to handle both large and small mouse events. This is because the parent object may have both 32-bit and 16-bit children. If it does, it will have to send out only small mouse events; otherwise, the 16-bit objects would be confused by the large mouse events.
Because 16-bit objects are the norm and not the exception, there are few requirements for them. However, 16-bit objects in 32-bit documents must do one thing: they must prevent the system from allowing the user to select the object and then drag-scroll too far. To prevent this from happening, the visible object must call
MSG_VIS_VUP_SET_MOUSE_INTERACTION_BOUNDS
to set a temporary boundary on drag scrolling.
MSG_VIS_VUP_EC_ENSURE_WINDOW_NOT_REFERENCED, MSG_VIS_VUP_EC_ENSURE_OBJ_BLOCK_NOT_REFERENCED, MSG_VIS_VUP_EC_ENSURE_OD_NOT_REFERENCED
VisClass
provides three messages you can use for special error checking. These three messages are provided especially to make sure that all objects being destroyed or removed will be destroyed cleanly. The default handlers for these messages should cause a fatal error if their criteria are not met.
void MSG_VIS_VUP_EC_ENSURE_WINDOW_NOT_REFERENCED(
WindowHandle window);
This message travels up the visible object tree, ensuring that the window handle passed is not stored anywhere that it might cause trouble. This message may be used when a window is being destroyed and its handle is about to be freed.
Source: Unrestricted.
Destination: Any visible object in the affected visible tree.
Parameters:
window
The handle of the window being destroyed.
Return: Nothing--if it returns, no error was encountered.
Interception: Do not intercept this message.
void MSG_VIS_VUP_EC_ENSURE_OBJ_BLOCK_NOT_REFERENCED(
MemHandle objBlock);
This message travels up the visible object tree, ensuring that the memory handle (the handle of an object block) passed is not stored anywhere that it might cause trouble. This message may be used just before the object block's handle is freed to ensure that no stale references will remain.
Source: Unrestricted.
Destination: Any visible object in the affected visible tree.
Parameters:
objBlock
The handle of the block being freed.
Return: Nothing--if it returns, no error was encountered.
Interception: Do not intercept this message.
void MSG_VIS_VUP_EC_ENSURE_OD_NOT_REFERENCED(
optr object);
This message travels up the visible object tree, ensuring that the optr passed is not stored by any objects in the tree. This message may be sent when the object is being destroyed; any objects methods encountering a match between a stored optr and the passed optr should force a fatal error.
Source: Unrestricted.
Destination: Any visible object in the affected visible tree.
Parameters:
object
The handle of the object being destroyed.
Return: Nothing--if it returns, no error was encountered.
Interception: Do not intercept this message.
It is possible, using visible object classes, to create your own specific UIs. It is a complex and difficult task, however, and only very few developers will expect to do this. Documentation on creating a custom specific UI may appear either in a future release of this documentation or under separate cover. Contact Geoworks Developer Products for more information.
Visible objects are involved in several basic operations, each of which has its own primary messages:
MSG_VIS_DRAW
( MSG_VIS_DRAW
) if they are to draw after their window has been exposed. Objects wishing to redraw themselves outside of exposure events can call
MSG_VIS_VUP_CREATE_GSTATE
( MSG_VIS_VUP_CREATE_GSTATE
) to create a GState in their view windows for drawing.
MSG_VIS_ADD_CHILD
( MSG_VIS_ADD_CHILD
), and the tree can be updated with
MSG_VIS_VUP_UPDATE_WIN_GROUP
( MSG_VIS_VUP_UPDATE_WIN_GROUP
).
MSG_VIS_REMOVE
( MSG_VIS_REMOVE
). This message will close the object (take it off the screen) and then segregate it from its parent.
MSG_VIS_MARK_INVALID
( MSG_VIS_MARK_INVALID
) in conjunction with
MSG_VIS_VUP_UPDATE_WIN_GROUP
( MSG_VIS_VUP_UPDATE_WIN_GROUP
) to cause the update.
MSG_VIS_DESTROY
( MSG_VIS_DESTROY
) first removes the object from the tree (with
MSG_VIS_REMOVE
) and then destroys it (through the
MetaClass
detach and destroy mechanisms).