Sequence Grabber Panel Components

This chapter describes sequence grabber panel components and explains how they are used. Because applications never call sequence grabber panel components directly, only developers planning to create panel components need to read this chapter.

A sequence grabber panel component presents a settings dialog box to the user that affects the behavior of a channel component. For example, a dialog might let the user control the frame capture rate of a video digitizer and the image quality of an image compressor. The user settings dialog box can be customized to include any required options by creating a new component.

How Sequence Grabber Panel Components Work

This section provides background information about sequence grabber panel components. After reading this section, you should understand why these components exist and whether you need to create one.

Sequence grabber panel components augment the capabilities of sequence grabber components and sequence grabber channel components by allowing sequence grabbers to obtain configuration information from the user for a particular digitizing source that is managed by a channel component. Consequently, sequence grabbers, channel components, and panel components have a close relationship.

Figure 4-1 shows this relationship and how these components interact with one another to place digitized data into a QuickTime movie.

../art/QTC-L-34.eps

Sequence grabbers present a settings dialog box to the user whenever an application calls the SGSettingsDialog function (see Sequence Grabber Component Functions for more information about this sequence grabber function). Applications never call sequence grabber panel components directly; application developers use panel components only by calling the sequence grabber component.

Although the sequence grabber creates the dialog box and manages its interactions with the user, portions of the dialog box are controlled by panel components and channel components.

Figure 4-2 shows a sample dialog box and identifies the various parts of the dialog box.

A sample sequence grabber settings dialog box

The sequence grabber creates the dialog box itself and manages the OK and Cancel buttons and the panel pop-up menu. Channel components are responsible for the monitor area on the right side of the dialog box. Panel components manage the settings area immediately below the panel pop-up menu. Only one panel component is active at any given time; the user selects a panel component by manipulating the panel pop-up menu.

When the user selects a specific panel component, the sequence grabber works with that component to build the panel settings dialog area and present it to the user. The panel component processes dialog events and mouse clicks as appropriate and validates the user’s settings. The sequence grabber then retrieves the settings from the panel component and stores those settings.

There are two circumstances under which you should consider creating a sequence grabber panel component:

If you have created special digitizing equipment, you may not have to create a special channel component for your equipment; the channel components provided by Apple may be sufficient for your needs. By providing a special panel component, however, you can allow the user to take advantage of your equipment’s special capabilities.

If you have created your own channel component, you must create an accompanying panel component to allow the user to configure your channel.

Creating Sequence Grabber Panel Components

This section discusses how to create a sequence grabber panel component. You should read this section if you are creating a panel component.

Applications do not call panel components directly. Rather, they invoke a sequence grabber’s settings dialog box by calling the SGSettingsDialog function. In response, the sequence grabber presents the settings dialog box to the user. When the user selects a specific settings panel, the sequence grabber invokes the appropriate panel component.

Panel components provide a number of functions that allow sequence grabbers to manage their relationships with panel components. See Managing Your Panel Component for complete descriptions of these functions.

Panel components are not responsible for saving their settings information. Sequence grabbers manage this information on behalf of panel components, and a sequence grabber may combine configuration information from several panel components in order to build up the complete configuration for an elaborate digitizing environment. Panel components provide functions that allow sequence grabbers to obtain this configuration information. See Managing Your Panel's Settings for more information about these functions.

Sequence grabbers store this configuration data in user data items. The Movie Toolbox provides a number of functions that allow you to create and manage user data items.

Apple has defined a component type value for sequence grabber panel components. You can use the following constant to specify this component type:

#define     SeqGrabPanelType 'sgpn'         /* panel component type */

Sequence grabber panel components use their component subtype and manufacturer values to indicate the type of configuration services they provide. The subtype value indicates the media type supported by the panel component. This value should correspond to the component subtype value of channel components that may be configured by the panel component. For example, a panel component that manages video settings would have a subtype of 'vide' (this value is defined by the Movie Toolbox’s VideoMediaType constant).

The manufacturer field contains a unique identifier for each panel component. The value should indicate something about the specific services provided by the component. For example, Apple has defined the following manufacturer values:

#define   SeqGrabCompressionPanelType  'sour'  /* input source selection */
#define   SeqGrabSourcePanelType       'cmpr'  /* compression settings */

In general, Apple has reserved all lowercase values of component subtypes and manufacturer codes.

Apple has defined a functional interface for sequence grabber panel components. You may use the following constants to refer to the request codes for each of the functions that your component must support:

enum {
    /* sequence grabber panel request codes */
    kSGCPanelGetDitlSelect         = 0x200,    /* SGPanelGetDITL */
    kSGCPanelCanRunSelect          = 0x202,    /* SGPanelCanRun */
    kSGCPanelInstallSelect         = 0x203,    /* SGPanelInstall */
    kSGCPanelEventSelect           = 0x204,    /* SGPanelEvent */
    kSGCPanelItemSelect            = 0x205,    /* SGPanelItem */
    kSGCPanelRemoveSelect          = 0x206,    /* SGPanelRemove */
    kSGCPanelSetGrabberSelect      = 0x207,    /* SGPanelSetGrabber */
    kSGCPanelSetResFileSelect      = 0x208,    /* SGPanelSetResFile */
    kSGCPanelGetSettingsSelect     = 0x209,    /* SGPanelGetSettings */
    kSGCPanelSetSettingsSelect     = 0x20A,    /* SGPanelSetSettings */
    kSGCPanelValidateInputSelect   = 0x20B
};

Before reading the rest of this chapter, you should have a basic understanding of how to create components. To create a sequence grabber panel component, you set up the global variables and implement the required Component Manager request codes and the functions that are private to your particular component. Then you manage the dialog box and work with the settings in the dialog box.

Managing Your Panel Component

Sequence grabber components load, configure, and unload your panel component. As part of this process, the sequence grabber installs your panel’s dialog items into the settings dialog box and may open your component’s resource file. Panel components provide a number of functions that allow the sequence grabber to manage its relationship with panel components. This section discusses those functions.

After opening a connection to your panel component, the sequence grabber identifies itself to your component by calling your SGPanelSetGrabber function. The sequence grabber then tries to determine whether your component can work with its associated channel component by calling your SGPanelCanRun function. The sequence grabber calls this function only if you have set the channelFlagHasDependency component flag to 1.

Once the sequence grabber has determined that your panel component can work with its channel component, the sequence grabber may open your component’s resource file (unless you have set the channelFlagDontOpenResFile component flag to 1). Once it has opened the resource file, it passes the file’s reference number to you by calling your SGPanelSetResFile function.

Next, the sequence grabber prepares to add your component’s items to the settings dialog box. The sequence grabber obtains your item list by calling your SGPanelGetDITL function. Once it has installed the items, it calls your SGPanelInstall function, giving you an opportunity to set initial values.

Before the sequence grabber removes your items from the settings dialog box, it calls your SGPanelRemove function.

Managing Your Panel's Settings

Sequence grabber components store their configuration information in Movie Toolbox user data items. This configuration information includes settings for each of the channels used by the sequence grabber. Because your panel component configures sequence grabber channels, your panel component is responsible for creating and formatting the contents of its user data items. The sequence grabber component calls your component whenever it wants to retrieve these settings. The sequence grabber may also use previously stored settings to restore your panel’s settings. This section discusses the functions that allow the sequence grabber to work with your panel’s settings.

The sequence grabber calls your SGPanelGetSettings function in order to retrieve your panel’s current settings. The sequence grabber uses your SGPanelSetSettings function to restore those settings to some previous values.

Component Flags for Sequence Grabber Panel Components

The Component Manager allows you to specify information about your component’s capabilities in the componentFlags field of the component description record. Sequence grabber panel components use the componentFlags field to indicate specific information about their capabilities.

The following flags are defined:

enum {
    channelFlagDontOpenResFile = 2,   /* do not open resource file */
    channelFlagHasDependency = 4      /* needs special hardware */
};

These flags control how sequence grabbers manage their connection with your panel component. The channelFlagDontOpenResFile flag instructs the sequence grabber not to open your component’s resource file. By default, the sequence grabber opens your component’s resource file for you, and then provides you with the appropriate file reference number. In general, this is convenient. However, if your component is linked with your application and does not have its own resource file, you may not want the sequence grabber to try to open the resource file. In such cases, set this flag to 1.

The channelFlagHasDependency flag allows you to tell the sequence grabber that your panel component requires special digitizing hardware. If you set this flag to 1, the sequence grabber gives your component an opportunity to verify that it can work in the current hardware environment by calling your component’s SGPanelCanRun function.

Processing Your Panel's Events

When your panel component is loaded into the settings dialog box and active, you may receive and process dialog events and mouse clicks.

Your component’s SGPanelEvent function acts like a modal-dialog filter function, allowing you to process individual dialog events. The sequence grabber calls your SGPanelItem function whenever the user clicks a dialog item.

Whenever the user clicks the OK button, the sequence grabber calls your SGPanelValidateInput function. Your panel component may then validate the user’s settings.

Implementing the Required Component Functions

Listing 4-1 illustrates the component dispatchers for a sequence grabber panel component together with the required functions for open, close, can do, and version.

Listing 4-1  Implementing functions for open, close, can do, and version

#define sgcPictShowTicksType 'TICK'
 
typedef struct {
    ComponentInstance           self;
    ControlHandle               ch;
} PictPanelGlobalsRecord, *PictPanelGlobals;
 
/* only for PICT channels */
pascal ComponentResult SGSetShowTickCount (SGChannel c,
                    Boolean show) = {0x2f3c,2,0x100,0x7000,0xA82A};
pascal ComponentResult SGGetShowTickCount (SGChannel c,
                    Boolean *show) = {0x2f3c,4,0x101,0x7000,0xA82A};
pascal ComponentResult PictPanelDispatcher
                    (ComponentParameters *params, Handle storage)
 
{
    OSErr err = badComponentSelector;
    ComponentFunction componentProc = 0;
    switch (params->what) {
        case kComponentOpenSelect:
            componentProc = PictPanelOpen; break;
        case kComponentCloseSelect:
            componentProc = PictPanelClose; break;
        case kComponentCanDoSelect:
            componentProc = PictPanelCanDo; break;
        case kComponentVersionSelect:
            componentProc = PictPanelVersion; break;
        case kSGCPanelGetDitlSelect:
            componentProc = PictPanelPanelGetDitl; break;
        case kSGCPanelInstallSelect:
            componentProc = PictPanelPanelInstall; break;
        case kSGCPanelItemSelect:
            componentProc = PictPanelPanelItem; break;
        case kSGCPanelRemoveSelect:
            componentProc = PictPanelPanelRemove; break;
        case kSGCPanelGetSettingsSelect:
            componentProc = PictPanelPanelGetSettings; break;
        case kSGCPanelSetSettingsSelect:
            componentProc = PictPanelPanelSetSettings; break;
    }
    if (componentProc)
        err = CallComponentFunctionWithStorage (storage, params,
                                                  componentProc);
    return err;
}
pascal ComponentResult PictPanelCanDo (PictPanelGlobals store,
                                          short ftnNumber)
{
    switch (ftnNumber) {
        case kComponentOpenSelect:
        case kComponentCloseSelect:
        case kComponentCanDoSelect:
        case kComponentVersionSelect:
        case kSGCPanelGetDitlSelect:
        case kSGCPanelInstallSelect:
        case kSGCPanelItemSelect:
        case kSGCPanelRemoveSelect:
        case kSGCPanelGetSettingsSelect:
        case kSGCPanelSetSettingsSelect:
            return true;
        default:
            return false;
    }
}
pascal ComponentResult PictPanelVersion (PictPanelGlobals store)
{
    return 0x00020001;
}
 
pascal ComponentResult PictPanelOpen (PictPanelGlobals store,
                                        ComponentInstance self)
{
    OSErr err;
 
    /* allocate global variables */
    store = (PictPanelGlobals) NewPtrClear
                (sizeof(PictPanelGlobalsRecord));
    if (err = MemError()) goto bail;
    SetComponentInstanceStorage (self, (Handle)store);
 
    /* remember the component instance identification number */
    store->self = self;
bail:
    return err;
}
pascal ComponentResult PictPanelClose (PictPanelGlobals store,
                                         ComponentInstance self)
{
    if (store) DisposePtr ((Ptr)store);
    return noErr;
}

Managing the Dialog Box

This section gives details on the functions that a panel component must provide so that the sequence grabber can load the component’s items into the settings dialog box and receive and process dialog events.

Listing 4-2 provides an example of the management of the settings dialog box for a sequence grabber that displays PICT images. The component item displayed in the dialog box in this case is a tick count checkbox.

Listing 4-2  Managing the settings dialog box

pascal ComponentResult PictPanelPanelGetDitl
                         (PictPanelGlobals store, Handle *ditl)
{
    /*
        Get and detach the dialog box template. Note that
        the sequence grabber has already opened the resource file.
    */
    *ditl = GetResource ('DITL', 7001);
    if (!*ditl) return resNotFound;
    DetachResource (*ditl);
    return noErr;
}
 
pascal ComponentResult PictPanelPanelInstall
                                (PictPanelGlobals store, SGChannel c,
                                 DialogPtr d, short itemOffset)
{
    Rect r;
    short kind;
    Handle h;
    Boolean ticksShowing;
    /* set up the initial state of the checkbox */
    GetDItem (d, 1 + itemOffset, &kind, &h, &r);
    store->ch = (ControlHandle)h;
    SGGetShowTickCount (c, &ticksShowing);
    SetCtlValue (store->ch, ticksShowing);
    return noErr;
}
pascal ComponentResult PictPanelPanelItem
                                (PictPanelGlobals store, SGChannel c,
                                 DialogPtr d, short itemOffset,
                                 short itemNum)
{
    /* if the item clicked was your checkbox, update its state */
    if ((itemNum - itemOffset) == 1) {
        Boolean showing = GetCtlValue (store->ch);
        SetCtlValue (store->ch, !showing);
        SGSetShowTickCount (c, !showing);
    }
    return noErr;
}
pascal ComponentResult PictPanelPanelRemove
                                        (PictPanelGlobals store,
                                        SGChannel c, DialogPtr d,
                                        short itemOffset)
{
    /* forget that it ever had a control */
    store->ch = nil;
    return noErr;
}

To allow the sequence grabber to work with your panel’s settings, your panel component must allow the sequence grabber to

Listing 4-3 gives an example in which the settings are managed in a user list that contains tick count information for a panel component for PICT images.

Listing 4-3  Managing the settings for a panel component

pascal ComponentResult PictPanelPanelGetSettings
                            (PictPanelGlobals store, SGChannel c,
                             UserData *result, long flags)
{
    OSErr           err;
    UserData        ud;
    Boolean         ticksShowing;
 
    /* create a user data list containing your state */
    if (err = NewUserData (&ud)) goto bail;
    if (err = SGGetShowTickCount (c, &ticksShowing)) goto bail;
    if (err = SetUserDataItem (ud, &ticksShowing,
                                 sizeof (ticksShowing),
                                 sgcPictShowTicksType, 1)) goto bail;
bail:
    if (err) {
        DisposeUserData(ud);
        ud = 0;
    }
    *result = ud;
    return err;
}
pascal ComponentResult PictPanelPanelSetSettings
                          (PictPanelGlobals store, SGChannel c,
                           UserData ud, long flags)
{
    Boolean ticksShowing;
    /* restore the state from the specified user data list */
    if (GetUserDataItem (ud, &ticksShowing,
                                sizeof (ticksShowing),
                                sgcPictShowTicksType, 1) == noErr)
        SGSetShowTickCount (c, ticksShowing);
    return noErr;
}