GEOS SDK TechDocs
|
|
4.6 Children of the View
|
4.8 Monitoring Input
When a document is larger than the view window, the user must have some means of navigation around it. The most common implementation of this is scrolling. In most situations, scrolling will be automatic when you use a view. However, you can modify the view's scrolling behavior.
HINT_VIEW_REMOVE_SCROLLERS_WHEN_NOT_SCROLLABLE, HINT_VIEW_SHOW_SCROLLERS_WHEN_NOT_SCROLLABLE
You can determine when scrollbars will be visible on your GVDA_SCROLLABLE view in several ways. One is to set the GVDA_DONT_DISPLAY_SCROLLBAR attribute, either dynamically or in your .goc file, to force a scrollbar not to be displayed. Another is to allow the user to use the GenViewControl to turn the scrollbars on or off.
A third is to allow the GenView to update itself dynamically, by using the hints
HINT_VIEW_REMOVE_SCROLLERS_WHEN_NOT_SCROLLABLE
and
HINT_VIEW_SHOW_SCROLLERS_WHEN_NOT_SCROLLABLE
.
The first causes the view to remove the scroller objects when scrolling is not needed (i.e. when the entire content or document fits inside the view's window). The second causes the view to show scrollers in all cases, as long as the view is GVDA_SCROLLABLE and GVDA_DONT_DISPLAY_SCROLLBAR is not set.
Views, by default, are not scrollable. To make your view scrollable, set the GVDA_SCROLLABLE attribute in both the
GVI_horizAttrs
and
GVI_vertAttrs
records. It is easiest to do this in your Goc code, as follows:
GVI_horizAttrs = @default | GVDA_SCROLLABLE; GVI_vertAttrs = @default | GVDA_SCROLLABLE;
You can also set these attributes during execution by sending the message
MSG_GEN_VIEW_SET_DIMENSION_ATTRS
to the view. See Dimensional Attributes
.
There are three basic ways scrolling can be initiated: First, the user can click on a special scroller object. Second, the user can initiate "drag scrolling" by clicking within the view and dragging outside the window's bounds. Third, the view's content object can request a scrolling action. Only the first of these three is activated by default.
When a scrollable view is first created, scroller objects are also instantiated. This is automatic and for the most part transparent to the geode. The scroller objects may be customized or placed in a certain spot in the generic tree: to learn how to do this, see Customizing the Scrollers .
Scrollers are generic by nature so they can conform to the specific UI in use; in OSF/Motif, for example, scrollers are manifested as scrollbars that position themselves at the right and bottom sides of the view. However, other specific UIs might implement dials, sliders, or some other gadgets for scrolling.
In normal scrolling, the user provides input to a scroller (for example, clicking on the up-arrow of a vertical scrollbar in OSF/Motif). The scroller then sends a message to the view indicating that a scroll should take place. The view calculates the new portion of the document and sends a
MSG_META_EXPOSED
to its content to indicate that the document must be redrawn. The content then draws its document to the view's window handle, and the view takes care of clipping the document and translating it to the screen.
To take advantage of the normal scrolling features, therefore, you only have to make the view scrollable and respond to
MSG_META_EXPOSED
.
MSG_GEN_VIEW_INITIATE_DRAG_SCROLL, MSG_GEN_VIEW_SET_DRAG_BOUNDS, HINT_VIEW_IMMEDIATE_DRAG_UPDATES, HINT_VIEW_DELAYED_DRAG_UPDATES
In many cases, applications will want to supplement normal scrolling with drag scrolling, in which a user clicks within the view and drags beyond its edge, causing the view to scroll in that direction. Also, some applications may wish to implement scrolling without the use of scrollers--drag scrolling provides a good way of doing this.
Two hints affect how drag scrolling is implemented.
HINT_VIEW_IMMEDIATE_DRAG_UPDATES
causes the view to be updated constantly during drags.
HINT_VIEW_DELAYED_DRAG_UPDATES
causes the view to be updated only at the end of drags. The default behavior is to update periodically during the drag in order to provide visual feedback to the user and to avoid excessive overhead in drawing repeatedly.
To implement drag scrolling, your view must be scrollable. It also must have the GVA_DRAG_SCROLLING attribute of the
GVI_attrs
record set. You can do this in Goc as follows:
GVI_horizAttrs = @default | GVDA_SCROLLABLE; GVI_vertAttrs = @default | GVDA_SCROLLABLE; GVI_attrs = @default | GVA_DRAG_SCROLLING;
You can also set the drag scrolling attribute by sending the view the message
MSG_GEN_VIEW_SET_ATTRS
(see The GVI_attrs Attribute
).
Normally, drag scrolling works only for the select button (in OSF/Motif, the left mouse button).
MSG_GEN_VIEW_INITIATE_DRAG_SCROLL
allows you to change this. For example, if you received a
MSG_META_START_MOVE_COPY
(indicating that the user used the direct-action button), you might want to initiate drag scrolling if your application does not support quick-transfer.
Additionally, if you wanted drag scrolling to work only in a portion of your document (for example, if you wanted the user to be able to move an object on the screen but only move it so far), you could set the temporary drag bounds directly after initiating the drag scrolling. This is done by sending the view a
MSG_GEN_VIEW_SET_DRAG_BOUNDS
.
void MSG_GEN_VIEW_INITIATE_DRAG_SCROLL();
This message instructs the view to begin drag scrolling until the pressed mouse button is let go by the user. When drag scrolling is enabled, the select button initiates it; this message allows initiation by any mouse button.
Source: Unrestricted--called by an application on a
MSG_META_START_
... mouse event.
Destination: The GenView in which the mouse button was clicked.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SET_DRAG_BOUNDS(@stack
sdword bottom, /* bottom scrolling bound */
sdword right, /* right scrolling bound */
sdword top, /* top scrolling bound */
sdword left); /* left scrolling bound */
This message sets a temporary rectangle in which drag scrolling can operate if the user should not drag scroll across the entire document.
Source: Unrestricted--called by an application on the initiation of drag scrolling.
Destination: The GenView in which the drag scrolling is underway.
Parameters:
bottom
,
right
,
top
,
left
The bounds (in document coordinates) of the rectangle limiting scrolling. These temporary bounds will be used only during the current drag scroll. The restriction will then be lifted.
Return: Nothing.
Interception: Generally not intercepted.
Many applications may find a need to scroll the view without user input or to modify the scrolling behavior of the view. For example, if your application has a trigger or menu item that brings a certain portion of the document onto the screen, you will need to instruct the view to scroll to that point, or perhaps your application must scroll by different increments depending on the situation.
MSG_GEN_VIEW_SCROLL_...
All typical messages sent by scrollers to the view are also available for sending by applications and other geodes. These messages are listed below. Note: With the exception of
MSG_GEN_VIEW_SCROLL
, these messages work only when the view is visibly initialized. This means that a view that is not on the screen will ignore these messages.
void MSG_GEN_VIEW_SCROLL(@stack
sdword yOffset, /* amount to scroll vertically */
sdword xOffset); /* amount to scroll horizontally */
This message causes the view to scroll a given amount in both the X and Y directions.
Source: Unrestricted.
Destination: Any GenView object.
Parameters:
yOffset
The signed vertical amount to scroll.
xOffset
Return: Nothing.
Interception: Generally not intercepted. If you want to alter scrolling behavior, see Tracking the Scrolling .
void MSG_GEN_VIEW_SCROLL_TOP();
Causes the view to scroll to the top of the document.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_PAGE_UP();
Causes the view to scroll up one window height.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_UP();
Causes the view to scroll up one increment.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_SET_Y_ORIGIN(
sdword yOrigin);
Causes the view to scroll to a given vertical point and sets the Y component of the origin to the passed value. It keeps the X component of the origin fixed.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_DOWN();
Causes the view to scroll down one increment.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_PAGE_DOWN();
Causes the view to scroll down one window height.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_BOTTOM();
Causes the view to scroll to the bottom of the document.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_LEFT_EDGE();
Causes the view to scroll to the document's left edge.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_PAGE_LEFT();
Causes the view to scroll left one window width.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_LEFT();
Causes the view to scroll left one increment.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_SET_X_ORIGIN(
sdword xOrigin);
Causes the view to scroll to a given horizontal point and sets the X component of the origin to the passed value. It keeps the Y component of the origin fixed.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_RIGHT();
Causes the view to scroll right one increment.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_PAGE_RIGHT();
Causes the view to scroll right one window width.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_SCROLL_RIGHT_EDGE();
Causes the view to scroll to the document's right edge.
Source: Unrestricted.
Destination: Any GenView object--views not visible will ignore these messages.
Interception: Generally not intercepted.
MSG_GEN_VIEW_MAKE_RECT_VISIBLE
You can easily make any portion of your document visible with the passage of a single message. For example, if you were displaying a map of the United States and the user clicked on a menu item to show the area around Cincinnati, you could easily determine the coordinates of Cincinnati and instruct the view to scroll there.
To make a certain rectangle of the document visible in the view, pass the message
MSG_GEN_VIEW_MAKE_RECT_VISIBLE
to the view. You can include a percentage to indicate how far through the rectangle the view should scroll--zero percent causing the rectangle to appear just at the near edge of the view and 100 percent causing the rectangle to appear just at the far edge. Fifty percent causes the object to be centered in the view window.
Normally, this message will not cause any scrolling if the rectangle is already on the screen. However, you can indicate that this message should always cause scrolling (useful if you want to center a rectangle that is already partially on the screen).
void MSG_GEN_VIEW_MAKE_RECT_VISIBLE(@stack
word yFlags, /* MakeRectVisibleFlags for y dimension */
word yMargin, /* percentage to scroll onto screen in y */
word xFlags, /* MakeRectVisibleFlags for x dimension */
word xMargin, /* percentage to scroll onto screen in x */
sdword bottom, /* bottom bound of the target rectangle */
sdword right, /* right bound of the target rectangle */
sdword top, /* top bound of the target rectangle */
sdword left); /* left bound of the target rectangle */
This message causes the view to scroll until a given portion of a passed rectangle is visible in the display window. If the rectangle is already partially visible, the view will not scroll unless instructed to do so by the flags arguments. If the view is not visibly initialized, this message will have no effect.
Source: Unrestricted.
Destination: Any GenView object.
Parameters:
yFlags
A record of flags indicating when and how scrolling occurs. See below.
yMargin
yMargin
of 50% centers the rectangle vertically; a
yMargin
of 100% puts the rectangle at the far edge of the screen from where it started. The percentages available are shown below.
xFlags
xMargin
xMargin
of 50% centers the rectangle horizontally; an
xMargin
of 100% puts the rectangle at the far edge of the screen from where it started. The percentages available are shown below.
bottom
,
right
,
top
,
leftReturn: Nothing.
Structures: The
yFlags
and
xFlags
parameters are of type
MakeRectVisibleFlags
; this type has the following values:
The percentages passed in
yMargin
and
xMargin
have a special format. You can use a predefined constant, or you can pass custom percentage. To use your own percentage, multiply the decimal representing the desired percentage (e.g. ".50" represents 50 percent) by the hexadecimal number 0xffff; or, instead of doing that math, you can use one of the following system-provided constants:
MRVM_0_PERCENT MRVM_25_PERCENT MRVM_50_PERCENT MRVM_75_PERCENT MRVM_100_PERCENT
Interception: Generally not intercepted.
MSG_GEN_VIEW_SUSPEND_UPDATE, MSG_GEN_VIEW_UNSUSPEND_UPDATE
If you cause the view to go through several scrolling operations in rapid order, you may want to suspend the view from sending a
MSG_META_EXPOSED
after each--it is much better to wait until all the updates have been made before the redrawing occurs.
To suspend a view's updates temporarily, send it the message
MSG_GEN_VIEW_SUSPEND_UPDATE
. After you have finished sending the scrolling messages, unsuspend the view's updates by sending
MSG_GEN_VIEW_UNSUSPEND_UPDATE
.
void MSG_GEN_VIEW_SUSPEND_UPDATE();
This message causes the view to suspend sending
MSG_META_EXPOSED
until it receives
MSG_GEN_VIEW_UNSUSPEND_UPDATE
. Suspend-unsuspend pairs can be nested.
Source: Unrestricted.
Destination: Any GenView object.
Interception: Generally not intercepted.
void MSG_GEN_VIEW_UNSUSPEND_UPDATE();
This message allows the view to send a
MSG_META_EXPOSED
again after being suspended with
MSG_GEN_VIEW_SUSPEND_UPDATE
.
Source: Unrestricted.
Destination: Any GenView object.
Interception: Generally not intercepted.
Warnings: It is an error to send this message to a non-suspended view.
MSG_META_CONTENT_TRACK_SCROLLING, MSG_GEN_VIEW_SETUP_TRACKING_ARGS, MSG_GEN_VIEW_TRACKING_COMPLETE
For flexibility, the view allows applications to track scrolling as it happens and alter it before it gets implemented. When GVA_TRACK_SCROLLING is set in
GVI_attrs
, all scrolling events will be sent to the content object before being implemented. Because there are often many scrolling events, you should avoid track scrolling unless truly necessary.
If you are going to track the scrolling, your content object
must
handle the message
MSG_META_CONTENT_TRACK_SCROLLING
. This message passes a
TrackScrollingParams
structure containing all the information needed about the upcoming scrolling event. When you receive it, you must do the following three steps:
MSG_GEN_VIEW_SETUP_TRACKING_ARGS
to the view
TrackScrollingParams
structure. You must call this routine to ensure that there are no synchronization problems with the scrolling event.
TrackScrollingParams
structure to the appropriate values.
MSG_GEN_VIEW_TRACKING_COMPLETE
to the view
TrackScrollingParams
structure based on your changes, then sends a message to the view with the new scrolling information. The view will then scroll according to your changes.
The
TrackScrollingParams
structure contains complete information about the scrolling event including context information, the view's width and height, the view's document origin, and the action in progress. It also contains a field called
TSP_change
, which is a structure of type
PointDWord
and should, after you change the scrolling, contain an offset from the proposed origin to the new origin you desire. See TrackScrollingParams and Associated Structures
for the definition of the structure.
Code Display 9-4 TrackScrollingParams and Associated Structures
/* * The TrackScrollingParams structure contains all the necessary information about * a given scrolling event. It is made up of several substructures, each of which * is shown below. */
/*
* ScrollAction is an enumerated type, each enumeration of which designates a
* different type of event. The handler should not change these.
*/
typedef ByteEnum ScrollAction; /* byte-length enumeration */
/* SA_NOTHING * No scrolling action
SA_TO_BEGINNING * Scrolling to beginning of document
SA_PAGE_BACK * Scrolling back one screen height or width
SA_INC_BACK * Scrolling back one increment
SA_INC_FWD * Scrolling forward one increment
SA_DRAGGING * Drag scrolling is underway
SA_PAGE_FWD * Scrolling forward one page
SA_TO_END * Scrolling to end of document
SA_SCROLL * Generic scrolling message sent
SA_SCROLL_INTO * Scrolling while keeping a point on screen
SA_INITIAL_POS * Indicating the initial scrolling position.
* Subsequent scroll messages will be relative to
* this origin.
SA_SCALE * Scaling may cause scrolling
SA_PAN * Pan-scrolling is underway. Otherwise
* identical to SA_SCROLL
SA_DRAG_SCROLL * Drag-scrolling, otherwise like SA_SCROLL
SA_SCROLL_FOR_SIZE_CHANGE * Scrolling because view size changed
*/
/* * ScrollFlags is a byte record of flags used to determine the type of scrolling * taking place and the context of the scroll. */
typedef ByteFlags ScrollFlags; #define SF_VERTICAL 0x80 /* Scrolling is vertical if set. If clear, * scrolling is horizontal. Invalid for * ScrollAction types SA_SCROLL_INTO, * SA_SCROLL, and SA_INITIAL_POS. */ #define SF_ABSOLUTE 0x40 /* Scrolling is to an absolute point. Set for * ScrollAction types SA_TO_BEGINNING, * SA_TO_END, SA_INITIAL_POS, SA_SCROLL_INTO, * SA_DRAGGING, and some SA_SCROLL. */ #define SF_DOC_SIZE_CHANGE 0x20 /* Scroll resulted from document size change. */ #define SF_WINDOW_NOT_SUSPENDED 0x10 /* Flag used internally only. */ #define SF_SCALE_TO_FIT 0x08 /* Flag used when the View is in scale-to-fit * mode (often changes scrolling behavior). */ #define SF_SETUP_HAPPENED 0x04 /* Flag for error checking only. */
/* * The TrackScrollingParams structure contains several elements, each of * which is described in the comments below. All the fields will be filled by * MSG_GEN_VIEW_SETUP_TRACKING_ARGS; however, only certain fields will be filled * by MSG_META_CONTENT_TRACK_SCROLLING. Therefore, you should always send * MSG_GEN_VIEW_SETUP_TRACKING_ARGS in the handler for this message. */
typedef struct {
ScrollAction TSP_action; /* The type of scrolling underway */
ScrollFlags TSP_flags; /* flags shown above */
optr TSP_caller; /* The sender of the scroll message */
PointDWord TSP_change; /* The relative amount being scrolled */
PointDWord TSP_newOrigin; /* The new absolute origin */
PointDWord TSP_oldOrigin; /* The original origin */
sword TSP_viewWidth; /* Current view width */
sword TSP_viewHeight; /* Current view height */
} TrackScrollingParams;
To set
TSP_change
, you must first understand how the entire
TrackScrollingParams
structure is used. When a scrolling event is being tracked, three sets of information are needed:
TSP_oldOrigin
.
TSP_newOrigin
.
TSP_oldOrigin
and
TSP_change
. You should set
TSP_change
understanding that it gets added to
TSP_oldOrigin
to produce the final origin of the view.
Tracking the scrolling, however, can introduce noticeable lag in scrolling speed. If you do not need to track the scrolling, you probably shouldn't. However, if you need to track the scrolling for simple or few changes, you should consider subclassing
GenViewClass
and altering the functionality of the method for
MSG_META_CONTENT_TRACK_SCROLLING
. The GenView's handler for this message simply passes the message on to the content.
If you just need to track changes to the origin, subclass
GenViewClass
and intercept
MSG_META_CONTENT_VIEW_ORIGIN_CHANGED
.
Code Display 9-5 Handling Track Scrolling
/* This message is sent by the view to its content object when track scrolling is * enabled and a scrolling event is begun. If you plan to track the scrolling, you * MUST handle this message. The first thing your handler should do is send * MSG_GEN_VIEW_SETUP_TRACKING_ARGS to the view. This message fills in the * TrackScrollingParams structure. The last thing the handler must do is send * MSG_GEN_VIEW_TRACKING_COMPLETE to the view. This message locks your changes * in and directs the view to implement them. * The format of this message is * void (TrackScrollingParams *args); */
@message MyProcessClass, MSG_META_CONTENT_TRACK_SCROLLING {
@call (args->TSP_caller)::MSG_GEN_VIEW_SETUP_TRACKING_ARGS(args);
/* Here you can do whatever you want to args->TSP_change. */
@call MyView::MSG_GEN_VIEW_TRACKING_COMPLETE(&args);
}
void MSG_GEN_VIEW_SETUP_TRACKING_ARGS(
TrackScrollingParams *args);
This message takes the
TrackScrollingParams
structure and fills in remaining fields not passed by
MSG_META_CONTENT_TRACK_SCROLLING
.
Source: The content object tracking scrolling (in the handler for
MSG_META_CONTENT_TRACK_SCROLLING
).
Destination: The calling object, found in
args->TSP_caller
.
Parameters:
args
A pointer to the mostly complete structure of
TrackScrollingParams
, to be filled in by the method.
Return: The structure pointed to by
args
will be filled.
Structures: See TrackScrollingParams and Associated Structures .
Interception: Generally not intercepted.
void MSG_GEN_VIEW_TRACKING_COMPLETE(
TrackScrollingParams *args);
This message sets the altered scrolling arguments and makes them official, instructing the view to implement them.
Source: The content object tracking scrolling (in its handler for
MSG_META_CONTENT_TRACK_SCROLLING
).
Destination: The calling object, found in
args->TSP_caller
.
Parameters:
args
A pointer to the completed structure of
TrackScrollingParams
.
Return: Nothing.
Structures: See TrackScrollingParams and Associated Structures .
Interception: Generally not intercepted.
void MSG_META_CONTENT_TRACK_SCROLLING(
TrackScrollingParams *args);
This message is sent by the GenView to its content if the content has requested track-scrolling (with GVA_TRACK_SCROLLING set in the GenView's instance data).
Source: Sent by a GenView object to its content when a scrolling event occurs and the view has GVA_TRACK_SCROLLING set.
Destination: The content of the GenView.
Parameters:
args
A pointer to a
TrackScrollingParams
structure.
Return: Nothing.
Structures: See TrackScrollingParams and Associated Structures .
Interception: Any content that tracks scrolling
must
handle this message. It should send
MSG_GEN_VIEW_SETUP_TRACKING_ARGS
and
MSG_GEN_VIEW_TRACKING_COMPLETE
to the object specified in
TSP_caller
.
HINT_VALUE_X_SCROLLER, HINT_VALUE_Y_SCROLLER
Although a view's scrollers should remain generic to maintain UI consistency, you may set your own GenValue objects to be the scrollers of your view. This allows special placement of the scrollers not only around the view but also within the generic object tree.
Before creating its own scrollers, the view will search for any objects below it in the generic object tree that have the hint HINT_VALUE_X_SROLLER or HINT_VALUE_Y_SCROLLER . For example, if you wanted to put your vertical scroller on the left of the view rather than on the right, you could add the following code:
@object GenViewClass MyView = {
/* other view attributes */
GI_comp = MyViewScroller;
}
@object GenRangeClass MyViewScroller = {
HINT_Y_SCROLLER;
HINT_SEEK_LEFT_OF_VIEW;
}
Custom scrollers do not need to be direct children of the view; instead, they may be any number of generations below the view in the generic object tree.
GEOS SDK TechDocs
|
|
4.6 Children of the View
|
4.8 Monitoring Input