In Part 1 of our Exploring CMac Series, we covered some supporting macros for the Delimited String Editing Dialog we are developing. In Part 2, we covered creating the dialog itself. In Part 3 we will add code to make the dialog function.
Now, on to the article...
Technical note: Dialogs in Multi-Edit consists of two layers, the Multi-Edit DlgCtrl or data layer, which consists of strings and editing windows that are directly accessed by Multi-Edit macros and the Windows Dialog controls or visible layer. Visible layers are handled by Windows and are what is seen on the screen. During dialog creation the values in the data layer are copied to the Windows control and are shown in the dialog. Windows handles all of the controls in the dialog and changes to the contents are done via Window messages. Any changes made in a
Windows control are not automatically changed in the Multi-Edit data layer. If the data needs to be accessible via the data layer, code needs to be run to synchronize the data between the two layers. The Dialog.s file has macros to do this in both directions.
There are a number of different ways to implement the dialog functional code. The most common is to write code to implement the Windows dialog message procedure in CMac code. It works directly with the Windows controls via Window Messages. This is how most of the dialogs in Multi-Edit are written. The big issue with this method are the ties from macros to Windows which would require them to each be rewritten if/when Multi-Edit is repurposed to allow it to work on other platforms. The way I chose to implement the functionality in our dialog uses code that was built into the
Dialog.s macros to allow writing macros that work with the data in the data layer and hides the Window specific code in the Dialog.s macros. This gives us the benefit of not having to do major code changes to make a dialog work when Multi-Edit is changed to run on other platforms. All that would be required is an update to Dialog.s code to rewrite those macros that are Windows specific to run on the new platform and all dialogs that use this method should continue to work. The dialog code in Template.s also use the general dialog code.
To start implementing the functionality of the Edit Delimited String Dialog, we first need to determine the behavior of each control in the dialog. First the two main buttons OK and Cancel will close the dialog and thus do not have to have anything special done in order for them to work. The Dialog.s code already handles these by closing the dialog and returning the /R= value they use. Thus to Return_Int value can be checked and the data from the dialog is process or ignored depending upon the value returned. The Help button is also handled completely by the Dialog.s code since the
/R=2 value is hard code to bring up the Help system. The rest of the buttons need additional parameters specified and code written to handle these parameters to change their default behavior, i.e. closing the dialog.
There are five additional buttons that we need to write code to implement, the Up and Down buttons will be used to move the selected string in the list up or down. The Replace button will be used to replace the selected string in the list with the string in the Path field and the Add button add the string in the Path field to the end of the list. The Delete button of course will delete the selected string from the list. To change the default behavior of a push button control and have it not close the dialog can be done by passing a "/M=macro" string as part of the last parameter to the DlgAddCtrl macro when
adding the control to the dialog.
When the dialog is run, selecting the button will cause the Dialog.s code to run the specified macro passing a few parameters to help identify the dialog, data and control id. Since each button macro will be similar we can start with a general framework that can be used as a starting point for each macro. This framework is shown below:
void _edsd_ButtonFunction( )
{
int Dlg=Parse_Int( "/DATAHANDLE=", MParm_Str );
if ( Dlg ) {
int LstWin =Parse_Int( "/LSTWIN=", MParm_Str );
int ActiveWin =Window_Id;
int SavRefresh =Refresh;
str TStr[ 1024 ];
Refresh=False;
if ( Switch_Win_Id( LstWin )) {
DlgSetFields( Dlg );
TStr=DlgGetStr( Dlg, id_eds_PathStr );
// add specific function code here
DlgUpdateCtrl( Dlg, id_eds_ListBox, 0 );
Switch_Win_Id( ActiveWin );
}
Refresh=SavRefresh;
}
} // _edsd_ButtonFunction
First we name each of the macros using the a _edsd_ prefix. The leading _ is being used to indicate this macro will not be called directly by a user but only by another macro. The edsd is used to identify the dialog the macro is being called by, i.e. EditDelimitStrDlg.
The common parameters that are passed to a button macro in the MParm_Str variable are:
/DATAHANDLE= The handle of the dialog
/DLGHANDLE= The window id of the main Windows dialog
/CTRLID= The id of the control being accessed.
Also for each of the buttons, the List control will need to be accessed. Inside the /M= macro string we will add the string "//LSTWIN=" + Str( LstWin ) to pass the Window_Id of the list window.
The DlgSetFields( Dlg ) call is used to copy the data from the Windows control back to the data layer. We can then read and use the control data and then the DlgUpdateCtrl( ... ) is used to move the data from the data layer back into the Windows control.
I could have implemented one macro for all buttons and check the CtrlId in that macro to determine which button is being selected. However I chose to write a separate macro for each button. See the code in the attached zip file for the details.
Access the zip file here: http://www.multieditsoftware.com/TheDev/article-files/StrTools3.zip
For the List box and Path string, we added "/CHANGEMAC=macro" and "/FOCUSMAC=macro" strings to the last parameter of the DlgAddCtrl call. The "/CHANGEMAC=" macro is called whenever a change to the control happens, i.e. a string is added or deleted from the list or the string is changed in the Path field. This allows updating the Path field when a different string is selected in the list. The "/FOCUSMAC=" macro is called when the control gets or loses focus, i.e. the focus to receive keyboard input.
The last special change is the addition of the "/PRELOOPMAC=macro" string to the DlgExecute call. This specifies a macro that gets called prior to the dialog being shown. We use this macro to update the Path field to show the selected string from the List. It is the exact same macro used by the List control when it changes.
The code to this point can be downloaded from here:
http://www.multieditsoftware.com/TheDev/article-files/StrTools3.zip
There is one more thing that we need to do to finish this series and that is to design and write a macro that we can use to interface our EditDelimitStrDlg to other dialogs so that they can edit the delimited string. This we will cover in Part 4 of the series.
Stay tuned.
Until the next Newsletter...
Happy Coding!
L. Dan Hughes, VP/CTO
Multi Edit Software, Inc.
danh@multieditsoftware.com
Input Your Suggestions in the Forum:
http://www.multiedit.com/forums/viewforum.php?f=7
**Please note that you can review/search
through all forum topics, but to submit a post
you must create a login identity.