Dopetrack Proxy
Availability
LightWave® 8.0 Component
Layout Header
lwdopetrack.h
The Layout Dopetrack allows the user to easily manage and
manipulate keyframes for the standard envelopes shared by all
Layout objects (i.e, Position, Rotation and Scaling). This
Global, specifically targeted towards the Layout Tool class,
allows a plug-in to take over most of the functionality of the
Dopetrack in order to "expose" to the user any
underlying envelopes that plug-in may have to offer.
Global Call
LWDopetrackProxy *dtprox;
dtprox = global( LWDOPETRACK_GLOBAL, GFUSE_TRANSIENT );
The global function returns a pointer to an LWDopetrackProxy
structure.
typedef struct st_LWDopetrackProxy
void (*toolRegister)(DTToolCallbacksID);
void (*toolRelease)(void);
void (*exposeEnvelopes)(LWEnvelopeID *,const char **,int *);
void (*refreshDisplay)(void);
DTKeySelectID (*querySelectedKeys)(void);
void (*querySelection)(LWTime *,LWTime *);
const LWTime *(*queryMarkers)(void);
void (*addMarker)(LWTime);
void (*remMarker)(LWTime);
DTBakeZoneID (*queryBakeZones)(void);
void (*addBakeZone)(LWTime,LWTime);
void (*remBakeZone)(LWTime,LWTime);
DTOperatingMode (*queryOpMode)(void);
void (*displayMenu)(DTMenuCallbacksID);
int (*visible)(void);
DTDrawFuncs drawfuncs;
} LWDopetrackProxy, *LWDopetrackProxyID;
Tool-class plug-ins register with the Dopetrack as soon as they
are activated. They must provide a pointer to a structure of
type DTToolCallbacks so that the Dopetrack may
interactive with them whenever the user takes some action on
their exposed Envelopes. The DTToolCallbacks
structure contains the following members:
typedef struct _dttoolcallbacks
{
DTUserEvent userEvent;
DTAllow allow;
DTMouse mouseEvent;
DTMenuCallbacks menu;
} DTToolCallbacks, *DTToolCallbacksID;
The DTMenuCallbacks structure contains the following
function pointers for handling context menu requests on the main
Dopetrack area:
typedef struct _dtmenucallbacks
{
DTMenuCount menuCount;
DTMenuSub menuSubMenu;
DTMenuSep menuSep;
DTMenuEnable menuEnable;
DTMenuItem menuItem;
DTMenuSelect menuSelect;
DTMenuSelect menuInitial;
} DTMenuCallbacks, *DTMenuCallbacksID;
Event Support
As the user interacts with the Dopetrack, certain events will
be passed back to the plug-ins. The userEvent
member of the DTToolCallbacks structure must be set
to the plug-in function that will be called with these events.
It is important to note that for a plug-in to utilize the
Dopetrack Proxy mechanism, this pointer must be set.
This function pointer is therefore not optional.
The function has the following prototype:
typedef void
(*DTUserEvent)(DTEventParamID);
The plug-in may control the available intrinsic functions of
the Dopetrack (those that remain active when the plug-in takes
control) using the allow function. This
function will receive a function type (see the table that
follows), and may return a true value (1) if that action may be
performed by the user, or a false value (0) if it is to be
disallowed. This function is optional, and leaving it NULL
will cause the Dopetracks default actions to be performed without
condition.
typedef int (*DTAllow)(DTKeyAction);
The function types that the allow function will be
one of the following:
|
Also optional is the mouseEvent function.
This allows the plug-in to receive mouse events (down, move and
up) whenever such events are generated in the Dopetrack margins.
typedef void
(*DTMouse)(DTMouseParamID);
Context Menu Support
The menu callback pointers of the DTMenuCallbacks
structure (nested within the DTToolCallbacks
structure) are optional, and allow the plug-in to completely
replace the Dopetrack's context menu with its own functionality.
The menuCount pointer should return the count of
items that your context menu will display, the menuItem
pointer should return the text for a specific menu item index, and
the menuSelect function will be called by the
Dopetrack when a selection is made from your plug-in's context
menu. The menuCount pointer is the key to
enabling context menus for your plug-in, and if you place a
pointer into the menuCount value, then you must also
at least define menuItem and menuSelect .
All other menu pointers are optional, and may contain NULL values.
typedef int
(*DTMenuCount)(int); typedef
int
(*DTMenuSub)(int,int); typedef
int *
(*DTMenuSep)(int); typedef
int
(*DTMenuEnable)(int,int); typedef
const char * (*DTMenuItem)(int,int);
typedef void
(*DTMenuSelect)(int,int); typedef
int
(*DTMenuInitial)(void);
To support certain internal functions, a return value of zero
(0) from your menuCount function will cause a -1
value to be sent to your menuSelect function.
Please code accordingly.
count = menuCount( menuID )
-
Returns the number of items that will appear on the menu
identified by
menuID . Your main menu will
always be identified by a menuID of zero (0).
Any sub-menus that you define off of that main menu will have a
menuID value assigned by the menuSubMenu()
function. So, if you have no sub-menus defined, menuID
will always be zero.
subMenuID = menuSubMenu( menuID, item )
-
Returns the menu identifier for any sub-menus that might be
defined on the menu
menuID . For example, if
your main context menu contained one sub-menu that branched from
the third menu element, then you would return a sub-menu
identifier for that sub-menu when menuID equals 0,
and item equals 2. This new menu identifier
will then be used in a call to menuCount() to query
the number of elements on that particular menu.
-
A return value of zero (0) indicates that the specified menu
element is not a sub-menu.
separray = menuSep( menuID )
-
Elements on a menu can be separated from one another using this
function. The returned array of integer values indicates
whether or not a separator should immediately follow the
corresponding menu element. A value of zero (0) means that
the corresponding menu element has no following separator, while
a value of one (1) indicates that a menu separator should follow
that element on the menu. The length of this array should
be of the exact size returned by the
menuCount()
function for the indicated menuID .
enable = menuEnable( menuID, item )
-
Menu items can be enabled or disabled for selection using this
function. A return value of zero (0) indicates that the
item on the specified menuID should be
disabled, while a value of one (1) indicates that is is available
for selection.
string = menuItem( menuID, item )
-
The Dopetrack will query the string values of menu elements using
this function. You should return a value appropriate for
the indicated
menuID and item offset.
menuSelect( menuID, item )
-
When a selection is made by the user, its owning menu identifier
and offset within that menu are provided back to the plug-in.
Keep in mind that
menuID may be a value previously
defined for a sub-menu, and will only refer to the main menu
elements when it has a value of zero (0).
select = menuInitial( )
-
An initial menu item selection can be specified by the plug-in
using this callback. The return value should be the
zero-based index of the menu item that should be highlighted when
the menu is displayed.
Exported Dopetrack Functions
toolRegister( callbacks )
-
Register with the Dopetrack so that it can act as a proxy for
your data.
callbacks is a pointer to a
structure of type DTToolCallbacks , and should be
appropriately populated.
toolRelease( )
-
When a plug-in is finished with the Dopetrack (for example, it is
dropped in favor of another tool), it should call this function
as part of its cleanup code.
exposeEnvelopes( envarray, axisnames, initstates )
-
Envelopes (and their attendant keyframes) are exposed to the user
through this function. The
envarray should be
a NULL-terminated list of LWEnvelopeID pointers that
are to be made available to the user on the Dopetrack.
Although any number of envelopes can be provided, you should be
aware that there is a threshold -- mandated by the current Layout
interface -- that will cause differences in behavior. If
you expose three or fewer envelopes, the Dopetrack will treat
them as it treats its normal channel processing -- that is, each
envelope will display as a separate 'tick' color on the Dopetrack
interface. However, if you expose more than three envelopes
at a time, a solid white bar will be displayed for any keyframe
at any time index found in the envelopes.
-
-
The
axisnames array allows the plug-in to re-define
and enable the axis buttons found in the lower left corner of the
Layout interface. The labels can be any string values
needed by the plug-in, but should be kept to a maximum of one
character for appropriate display. Up to three axis labels
may be defined As the user interacts with these axis
buttons, events are generated back to the plug-in regarding their
state.
-
-
initstates is another array that runs parallel to
the axisnames array. It indicates, by either a one
(1) or a zero (0), whether or not the corresponding axis button
should be initially enabled or disabled.
-
Please note that the pointers you provide for
envarray
and axisnames should be persistent in your code
(i.e., declared static ally). The Dopetrack
Proxy does not make a copy of the value you provide, rather it
simply caches the pointer and references it as needed.
updateDisplay( )
-
As the plug-in makes changes to its exposed envelopes (whether
through the normal course of its processing, or in response to a
Dopetrack event), it should call this function to refresh the
keyframe information displayed by the Dopetrack. Display
updating is not automatic; the Dopetrack does not track volatile
changes to your envelopes.
selarray = querySelectedKeys( )
-
When an event is generated that the plug-in has allowed to occur
(implicitly or explicitly), the currently selected keyframes
indices can be determined using this function.
selarray
is a pointer to a structure of the following type:
typedef struct _dtevent_keyselect_st
{ int
count;
LWTime *indices;
LWTime offset;
} DTKeySelect, *DTKeySelectID;
- Time indices selected by the
user will appear in the
indices array (of count
length). If a shift of keyframes has taken place, the
offset (as a delta) is provided.
-
A
NULL value will be returned if no keyframes are
currently selected by the user.
markerarray = queryMarkers( )
-
The user can flag individual time indices by dropping "markers"
on them. While these markers are not used internally by
the Dopetrack, they can be queried by a plug-in and processed in
some context-specific fashion.:
-
The
markerarray is a linear array of LWTime values,
terminated by a time value of 99999.0 (defined in the
lwdopetrack.h header as TIME_MARKER ).
A NULL value will be returned if no markers are
currently defined by the user.
addMarker( at )
-
A marker can be dropped onto the Dopetrack by the plug-in using
the function. The
at parameter is the time
index where the marker should appear.
remMarker( at )
-
An existing marker on the Dopetrack can be removed using this
function. The
at parameter is the time index
where the marker resides.
bakearray = queryBakeZones( )
-
The user can define ranges of frames on the Dopetrack. The
plug-in can use these ranges for whatever purpose suites its
context. This function returns a pointer to a structure of
the following type:
typedef struct _dtevent_bakezone_st
{ int
count;
//
parallel arrays
int
*start_frame,*end_frame;
LWTime *start_time,*end_time;
} DTBakeZone, *DTBakeZoneID;
- A
NULL value will
be returned if no Bake Zones are currently defined by the user.
addBakeZone( start, end )
-
The plug-in can define its own baking zone ranges on the
Dopetrack using this funciton.
start and end
define the boundaries of the baking zone as time indices.
remBakeZone( start, end )
-
The plug-in can destroy a baking zone using this funciton.
start and end define the boundaries of
the baking zone to match.
querySelection( start, end )
-
If a user-defined selection exists on the Dopetrack (typically
from a drag-select using the right mouse button), the range of
the selection can be determined using this function. The
start and end arguments are pointers to
storage of type LWTime , and will be filled in with
the beginning and ending time indices of the current selection.
If these values are identical, then no user-defined selection
currently exists on the Dopetrack.
opmode = queryOpMode( )
-
The Dopetrack will operate globally on all nine channels at one
time, or discretely on a per-channel basis, depending upon the
mode selected by the user. This function will return a
value of type
DTOperatingMode , which will be one of
DTOPMODE_CHANNEL or DTOPMODE_GLOBAL .
Plug-ins are not required to adhere to this user-selected mode,
as their context may or may not be conducive to such operational
types.
displayMenu( menuCallbacks )
-
When the user clicks the right-mouse button on the Dopetrack, the
Dopetrack API will automatically query the plug-in for a context
menu using any menu callbacks functions defined when the plug-in
registered. However, there may be times when the plug-in
will need to display a context menu for its own data in the left
or right margins of the Dopetrack (see the Tool Drawing
section later in this document).
-
This function call allows the plug-in to display an on-demand
context menu. The
menuCallbacks pointer
containers the menu callback functions to be used in generating
and processing the context menu. When the user is finished
with the menu, the resulting menuID and selected item will be
reported back to the menuSelect callback for the
plug-in to process, in exactly the same fashion as when the
Dopetrack demands a context menu from the plug-in.
open = visible( )
-
The Boolean returned by this function indicates whether or not
the Dopetrack is open (and, thus, visible to the user) or closed.
Interaction
As mentioned before, events will be generated by user
interactions, and these events will be passed on to the registered
plug-in. Events are passed to the userEvent
function by a pointer to the following structure:
typedef struct _dteventparam_st
{ DTEventType
event;
int value;
LWTime offset;
} DTEventParam, *DTEventParamID;
The event value will be one of the following::
|
Tool Drawing
The margins to the left and right of the open Dopetrack are
available to plug-ins for their drawing needs. Using a
series of exported drawing functions, the plug-in can display any
information in these areas that will aid the user in their
interactions.
The drawfuncs member of the LWDopetrackProxy
structure contains a list of drawing functions that the plug-in
can be used to update either of these two margin areas.
typedef struct _dtdrawcallbacks
{ int
*(*context)(int side);
void (*erase)(int x,int y,int w,int h);
void (*pixel)(int x,int y,int color);
void (*line)(int x1,int y1,int x2,int y2,int
color); void
(*rectOutline)(int x,int y,int w,int h,int color);
void (*rectFilled)(int x,int y,int w,int h,int
bcolor,int fcolor);
void (*border)(int x,int y,int w,int h);
void (*divider)(int x,int y,int w);
void (*text)(int x,int y,int color,const char
*text); void
(*text_box)(int x,int y,int w,int h,const char *text);
void (*button)(int x,int y,int w,int h,const char
*text); void
(*flush)(void); } DTDrawFuncs,
*DTDrawFuncsID;
dim[2] context( side )
-
Before performing any drawing, the plug-in should make a call to
this function to select the margin context to receive the drawing
action. A value of zero (0) chooses the left margin, and a
value of one (1) chooses the right margin. An integer
pointer is returned that contains the width and height dimensions
of the selected margin.
erase( x, y, w, h )
-
Erases the specified area of the drawing context to the
appropriate background color/image.
pixel( x, y, color )
-
Draws a single pixel in the specified color at the indicated
location.
line( startx, starty, endx, endy, color )
-
Draws a line segment in the specified color between the start and
end coordinates.
recOutline( x, y, w, h, color )
-
Draws a rectangular box using the specified line color.
recFilled( x, y, w, h, bordercolor, fillcolor )
-
Draws a rectangular box using the specified line
bordercolor
for the outline, and the interior using the specified fillcolor .
border( x, y, w, h )
-
Draws a 3D-look rectangular border.
divider( x, y, w )
-
Draws a 3D-look line divider.
text( x, y, color, text )
-
Draws provided text string at the indicated location with the
specified color.
text_box( x, y, w, h, text )
-
Draws provided text string within the specified bounding box.
This function is intended for use with RichText strings.
button( x, y, w, h, color )
-
Draws a button in the current LightWave interface style.
x
and y are the column and row position of the upper
left corner of the button. w and h
are the width and height, respectively. You can
subsequently use the text() or text_box()
functions to draw a label upon the button face.
flush( )
-
Causes an immediate re-draw of the Dopetrack, along with its left
and right margin areas.
Mouse Events
In addition to drawing capabilities, plug-ins can register for
events in these areas, creating a two-way interface mechanism,
effectively providing these two margin areas to the plug-in for
their own, context-specific interface needs. In order to
receive mouse events in these areas, the plug-in needs to fill in
the pointer for the mouseEvent function when it registers with the
Dopetrack.
Three event types are provided to the plug-in's event callback,
defined by the following constants:
typedef enum
{
DTMOUSE_DOWN,
DTMOUSE_MOVE,
DTMOUSE_UP } DTMouseEvent;
When an event occurs, the callback function will be passed a
pointer to a DTMouseParam structure.
typedef struct _dtevent_mouse_st
{ DTMouseEvent
event; int
context; int
x,y; int
w,h; int button;
} DTMouseParam, *DTMouseParamID;
event
-
Contains one of
DTMOUSE_DOWN , DTMOUSE_MOVE ,
DTMOUSE_UP .
context
-
Will hold a zero (0) if the event took place in the left margin
of the Dopetrack, or one (1) if it occurred in the right margin.
x,y
-
The location of the event. The values are relative to the
boundaries of the margin area.
w,h
-
Indicates the dimensions of the margin area where the event
occurred.
button
-
Indicates which mouse button was pressed. Will hold zero
(0) for left, one (1) for right, and (2) for the middle button.
Examples
The following code fragments provide a better understanding of
the use of the Dopetrack Proxy mechanism.
Registration
static DTToolCallbacks dtcallbacks = {
_dtUserEvent,
_dtAllow,
_dtMenuCount,
NULL,
// no sub-menus defined
_dtMenuSep,
NULL,
// menu items always
enabled
_dtMenuItem,
_dtMenuSelect }; ....
dtprox =
(LWDopetrackProxyID)(*global)(LWDOPETRACK_GLOBAL,GFUSE_TRANSIENT);
if(dtprox)
(*dtprox->toolRegister)(&dtcallbacks);
Envelope Exposure
static LWEnvelopeID expose[4];
static const char * channel_names[] = {"L","C","M",NULL};
static int
channel_states[] = {1,0,1}; ...
dtprox =
(LWDopetrackProxyID)(*global)(LWDOPETRACK_GLOBAL,GFUSE_TRANSIENT);
if(dtprox)
(*dtprox->exposeEnvelopes)(expose,channel_names,channel_states);
Support Functions
void _dtUserEvent(DTEventParamID
event) {
DTKeySelectID selected_keys;
LWDopetrackProxyID dtprox;
dtprox =
(LWDopetrackProxyID)(*GLOBAL)(LWDOPETRACK_GLOBAL,GFUSE_TRANSIENT);
if(!dtprox) return;
switch(event->event)
{
case DTEVENT_KEYFUNCTION:
// the user has performed some action on the exposed
keys
// regardless of the action, get the selected key
times
selected_keys = (*dtprox->querySelectedKeys)();
if(!selected_keys) break; // nothing selected
switch(event->value)
{
case DTACTION_SELECT:
break;
case DTACTION_SHIFT:
break;
case DTACTION_SHIFT_COPY:
break;
case DTACTION_CREATE_KEY:
break;
}
break;
case DTEVENT_EDITSTATECHANGE:
// the state of an axis button has changed. event->value
is:
// 'X' if(1<<0) (axis is enabled)
// 'Y' if(1<<1) (axis is enabled)
// 'Z' if(1<<2) (axis is enabled)
break;
case DTEVENT_UNDO:
// undo my last action
break;
case DTEVENT_REDO:
// redo my last action
break;
default:
// any other actions are context explicit, and
// come only from any menu the plug-in may chose
// to provide (see the menu functions below...)
break; }
}
int _dtAllow(DTKeyAction action)
{ // this function
controls the intrinsic actions available
// to anybody using the Dopetrack -- keyframe selection,
movement, // and
value copying. the tool plug-in can allow or disallow
// any of these specific functions.
// any functionality beyond this is strictly defined by
the // tool plug-in,
and exposed to the user via the context menu
// mechanism.
switch(action)
{
case DTACTION_SELECT:
// allow the user to select exposed keyframes?
break;
case DTACTION_SHIFT:
// allow the user to move selected keyframes to a new
location?
break;
case DTACTION_SHIFT_COPY:
// allow the user to copy values from selected
keyframes
// to create new ones at a new location?
break;
case DTACTION_CREATE_KEY:
// allow the user to create a new keyframe?
break;
default:
return(0); // in case new options are added
}
return(0);
}
int _dtMenuCount(int menuID)
{ LWTime
start,end;
LWDopetrackProxyID dtprox;
// how many menu items will be displayed?
if(menuID == 0) // main context menu
{
dtprox =
(LWDopetrackProxyID)(*GLOBAL)(LWDOPETRACK_GLOBAL,GFUSE_TRANSIENT);
if(!dtprox) return(0);
(*dtprox->querySelection)(&start,&end);
if(start == end) // no selection exists
return(3);
return(2);
// "Moe" is only available with a selection
}
return(0);
// no sub-menus defined, so nothing more to check
}
const char * _dtMenuItem(int
menuID,int num) {
static const char *menu_items[] =
{"Larry","Curly","Moe"};
if(menuID == 0)
return(menu_items[num]);
return(NULL); // no sub-menus defined
}
int * _dtMenuSep(int menuID)
{ static int
*menu_seps[] = {
0, //
1, // separator following "Curly" on
menu
0 }; //
if(menuID == 0) // main context menu
return(menu_seps);
return(NULL); // no sub-menus defined
}
void _dtMenuSelect(int menuID,int
num) {
LWDopetrackProxyID dtprox;
// the user selected one of my menu items. perform
// the processing.
dtprox =
(LWDopetrackProxyID)(*GLOBAL)(LWDOPETRACK_GLOBAL,GFUSE_TRANSIENT);
if(!dtprox) return;
if(menuID == 0)
{
switch(num)
{
case 0: // Larry
break;
case 1: // Curley
break;
case 2: // Moe
break;
} }
}
|