Tutorial step 6: supporting user configuration |
||
|
The next logical step is allowing the user to choose between half and third color ramp reduction, and to enable or disable the 2x scaling. This requires two extra routines, configProc and stringProc2.
The configProc and stringProc2 functionsconfigProc is simple: it brings up a dialog box. This requires an extra parameter to the usual template: Function configProc(fa: PFilterActivation; const ff: PFilterFunctions; hWnd: HWND): Integer; cdecl; When called, configProc should open up a modal dialog box. Return zero for OK, and non-zero for Cancel, but modify configuration parameters on OK only. VirtualDub doesn't care about the return parameter normally, except when a filter is first added to the chain; here VirtualDub calls configProc immediately, and if the user cancels the dialog box, the filter instance is destroyed. Note: You'll probably need the HINSTANCE of your filter module to open the dialog box. Fortunately, VirtualDub provides this value for you as fa^.filter^.module^.hInstModule, so you won't have to write a DLL entry routine to cache the instance pointer. stringProc2 is an advancement of stringProc. They both receive the address of a string buffer (i.e. a null-terminated string) to fill. The diference between the two is that stringProc2 receives also in maxlen the number of characters available in the buffer, while stringProc doesn't and you risk overrunning it:
Procedure stringProc(const fa: PFilterActivation; const ff: PFilterFunctions; var buf: PChar); cdecl; The purpose of stringProc is to give a quick overview of a filter instance's settings on the filter list. For instance: 320x240 640x480 resize (bilinear) The buf parameter points right after the name, and the usual course of action is to supply the buffer to StrCopy or StrLCopy. By convention, filters should add the space and specify the parameters in parentheses. Starting in VirtualDub version 1.4.11 you have to provide the function stringProc2. If you want to keep compatability with previous versions of VirtualDub then you have to provide also the function stringProc. Adding user configurationTo create a config dialog box, create a new form in Delphi and set the form property BorderStyle to bsDialog, the property FormStyle to fsStayOnTop and the property Position to poDesktopCenter. Add the OK and Cancel buttons, and add a checkbox for the selection of double width and a radiogroup for choosing between the division by 2 or by 3 (half or third color ramp reduction). In the config form unit fileNext, we'll need to update TFilterData to hold the new fields. The declaration of TFilterData needs also to move from our main delphi project file to the form Unit file, to avoid having both files referencing each other under the uses clause. In a more complex filter involving several files the declaration of TFilterData, other types to be used throughout the project and general variables can be declared in an independent Unit shared by the several files of the project.
PFilterData = ^TFilterData; When creating more complex dialog boxes, you might find the need to store temporary items, such as GDI brush handles; the easiest way to do this is simply to stick them in your instance data structure. We need a variable to hold the address of the filter data while the user is configurating the filter. One way to do it is to declare it as a field in the form declaration.
TConfigForm = class(TForm) Next we need to set up two event handlers. One to initialise the controls in the form that should run when the configuration form is created. And another to update the filter data when the user presses OK.
procedure TConfigForm.FormCreate(Sender: TObject); Finally, the CreateParented method from the class TForm is overriden in the TConfigForm subclass for reasons that will be explained next.
constructor TConfigForm.CreateParented(ParentWindow: HWnd; aFilterData: PFilterData); Our config form unit file should now look like this. Note: You can delete the declaration of the variable for the form that Delphi includes by default, because it will be crated dinamicaly by the CreateParented constructor. In the main project fileNow we need the configProc and stringProc functions. The configProc function will create an instance of the form declared in the form unit file, using the method CreateParented, inherited from the TForm class. CreateParented creates and initializes a control as the child of a specified non-VCL container, in this case VirtualDub which handle is given by the parameter hWnd. In this case the CreateParented from TForm is overriden in the TConfigForm subclass to allow the passage of the filter instance data.
Function tutorialConfigProc(fa: PFilterActivation; const ff: PFilterFunctions; hWnd: HWND): Integer; cdecl; Add the new functions to the FilterDefinition structure:
configProc: tutorialConfigProc; We need to rewrite paramProc as well, to switch between 1x and 2x modes.
Function tutorialParamProc(fa: PFilterActivation; const ff: PFilterFunctions): Integer; cdecl; Finally, adjust startProc to generate a half lookup table as well, and runProc to allow non-expansion. The decision between halving and thirding color components is folded into the lookup tables, so there's no need to check the flag at runtime.
Function tutorialStartProc(fa: PFilterActivation; const ff: PFilterFunctions): Integer; cdecl;
Function tutorialRunProc(const fa: PFilterActivation; const ff: PFilterFunctions): Integer; cdecl; Whew! This one involved a bit of coding. Modifying this structure for other filters is easy, though. Check here how the main project file of the filter should look like and here the config form unit file. |
||
© 2005 Fernando Reis < >Adapted from VirtualDub external filter SDK 1.05 documentation © 1999-2001 Avery Lee |