to open the X-Function in Code Builder, where we can write our Origin C code.
There are two buttons near the top of the editor window: a Compile button and a Return to Dialog button
. The Compile button is used to compile your X-Function's Origin C code. The Return to Dialog button will close the editor window and return you to the X-Function Builder dialog.
In the editor you will notice some of the Origin C code has a gray background. These parts of the code are read-only and cannot be changed. The X-Function framework generated these parts of the code and they are in a required syntax.
You can include additional header files in your X-Function's Origin C code. While not required, it is recommended that you include your additional header files near the top of the file, after the following line:
//put additional include files here
This recommendation is to help keep the file organized and to be consistent with other X-Functions.
When you include files using the < and > brackets, then those files are included from the Origin C System folder located in the Origin installation folder. You can still provide a relative path to move above the System folder. These brackets behave the same when compiling .c and .cpp files in Origin C.
// Include fft_utils.h located in the "OriginC\System" folder. #include <fft_utils.h> // Include abffiles.h located in the "OriginC\OriginLab" folder #include <..\OriginLab\abffiles.h> // relative path
When you include files using double quotes, then those files are included from the "OriginC\X-Functions" folder in your "User Files" folder. This behavior is different than when you compile a .c or .cpp file in Origin C. This different behavior is necessary because X-Functions are installed in a location maintained by Origin.
// Include myOtherHeader.h located in the "OriginC\X-Functions" // folder of the "User Files" folder. #include "myOtherHeader.h"
If you specify an absolute path between double quotes, then that file will be included regardless of where the file is located.
In X-Function Builder's Tree View there is an option named Auto Compile Dependent Files. When this option is turned on it will cause the compiler to check for a .c or .cpp file sharing a name with an included .h file. If a .c or .cpp file is found then it will be loaded and compiled too.
// Include graph_utils.h located in the "OriginC\Originlab" folder // If Auto Compile Dependent Files is turned on // then graph_utils.c, located in the same folder, will be loaded and compiled #include <..\Originlab\graph_utils.h>
In order to provide more clarity and readability, to make your code easier for future understanding and maintenance, it is recommended that you break a long function into functionally independent and well-structured short functions, which is also proposed in some other programming languages. In an X-Function, you can add these short functions in as internal functions with the keyword static after the following line.
//put your own support static functions here
For example, in many X-Functions with lots of interaction from the GUI, many codes will be needed in xfname_event1( ), and then you can add a static function, similiar to Origin's interp1 X-Function.
static void _update_method_show(TreeNode& trGetN)
As you can see, it is also recommended that you use an underscore to separate the components in a function name.
The main function is where you put all the code that performs the primary tasks of your X-Function.
Your X-Function's main function will have the same name you gave your X-Function in X-Function Builder. For example, if you named your X-Function myXFunc then the main function will also be named myXFunc.
The arguments passed to the main function are the variables listed in the X-Function Builder dialog. All the variables set as Input are passed in as constant references while the variables set as Output or Input/Output are passed in as writable references.
Your X-Function's source code contains functions used for handling various events. The name of each event handler function is prefixed with the X-Function's name followed by an underscore character followed by the event name. For example; if your X-Function's name is myXFunc then the before_execute event handler function will be named myXFunc_before_execute.
The following is a list of events:
By default all the event handler functions are empty. You only need to add code to an event handler function when you want to change the default behavior or do some additional processing during an event.
The following sections provide more details about each of the event handler functions including their purpose, parameters passed in, and return type.
This function will be called before execution of the main function and will be called two or three times.
Prototype
void xfname_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
Parameters
trGetN
A TreeNode containing the variables passed to the X-Function.
nGetNDialog
An integer value indicating when the function is being called.
A value greater than zero indicates the function is being called before showing its dialog. This happens when choosing Open Dialog from a menu, programmatically calling the X-Function with the -d option, or choosing Change Parameters for a manual recalculate.
Value | Before Opening Dialog for... |
---|---|
1 | Simple GetNBox |
2 | GetNGraphBox with Preview |
3 | GetNImageBox |
A value of -1 indicates the dialog was closed by the user clicking the OK button.
A value of zero indicates the main function is about to be called.
nRet
This option can control the execution states of the X-Function.
XFEVT_PROCEED = 0 // Follow with normal execution XFEVT_ABORT = 1 // Abort execution XFEVT_PROCEED_NO_DLG = 2 // Execute silently without opening dialog.
dwCntrl
This option can be used to determine how this X-Function is accessed. Possible values are enumerated as:
LTXF_FROM_GUI_MENU // Accessed from menu LTXF_FROM_GUI_PROMPT // Accessed from command window LTXF_FROM_AUTO_UPDATE // Accessed for Auto-update LTXF_FROM_FUNCTION // Accessed from Origin C function LTXF_THEME_USED // Theme is used LTXF_CHANGE_PARAM // Accessed for Change Parameters
The following example shows how to check if the X-Function is accessed from the command window and a theme is also used (type xfname -t themename in the command window).
if(!(dwCntrl & LTXF_FROM_GUI_PROMPT) && (dwCntrl & LTXF_THEME_USED)) { // handle this case }
This function is called once for each TreeNode variable passed to the X-Function. The calls occur before the before_execute function is called.
Prototype
int xfname_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
Return
Return zero to update the dialog or -1 to not update the dialog. The default behavior returns -1.
Parameters
tr
The TreeNode to be created, which should have been defined as an input TreeNode type variable of the X-Function.
lpcszVarName
The name of the TreeNode variable.
These are the primary event handling functions. They will be called by any event, such as dialog initialization, changes to any settings in the dialog, button clicking, and more. These functions are only used in X-Functions with a simple GetN dialog. X-Functions with a graph preview or an image preview use a different set of event handler functions and are discussed in a later section.
Prototype
int xfname_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
Return
If returning true, the dialog will be updated.
Parameters
trGetN
This is the tree node of the variables defined in the X-Function.
nRow
The index of the row of the value-changed control node in TreeNode trGetN. The value will be -1 when the event is not 'control value changed'.
nEventID
Event type ID. For example, GETNE_ON_INIT, GETNE_ON_THEME.
dwEnables
This parameter is used to enable or disable the OK, Apply or other custom button. It is true by default, and will usually be set to false when the user's settings are invalid, so as to disable the OK or Apply button.
lpcszNodeName
If the event is generated by a control change in the dialog, it will be the variable name of this control. Otherwise, it will be an empty string.
DynaCntrlContainer
X-Function dialog window container.
strAux
This parameter is the auxiliary string, which is for advanced usage. Please refer to the header file <Origin Installation Directory>\OriginC\System\GetNBox.h for more details like the following definition.
#define DLG_NEED_CHANGE_GRID "GETN_CHANGE_GRID" #define GETN_CHANGE_GRID set_aux_value(strAux, DLG_NEED_CHANGE_GRID);
strErrMsg
This is the string message that will be shown in the bottom of the dialog. It is usually used to notify the user of any errors that occurred during the input of variable values.
The event1 and event1_ex event handler functions are not used by X-Functions that have a graph preview dialog. Instead you use the GetNGraphPreview functions.
See the Creating Graph Preview GetN Dialog section for an example of how to create an X-Function with a graph preview dialog.
The event1 and event1_ex event handler functions are not used by X-Functions that have an image preview dialog. Instead you use the GetNImageBox functions.
See the Creating Image GetN Dialog section for an example of how to create an X-Function with an image preview dialog.
When a user passes a bad value to your X-Function and also passes the -d option, or enters a bad value in the X-Function's dialog, you can display an error message in the dialog by setting the strErrMsg argument passed into the event handler function.
Which event handler function is called depends on the GetN Dialog your X-Function uses.
GetN Dialog Used | Event Handler Function |
---|---|
Simple GetNBox | xfname_event1 |
GetNGraphBox with Preview | GetNGraphPreview_OnChange |
GetNImageBox | GetNImageBox_OnChange |
Let us assume we have an X-Function that accepts an integer variable named x1. The following code snippet, inserted into the appropriate event handler function, checks the x1 variable's value to see if it is less than zero or greater than 100. If it is then it sets the strErrMsg to an appropriate message to display in the dialog, and also disables the OK button. If the value is within the accepted range then it simply makes sure the OK button is enabled.
if( trGetN.x1.nVal < 0 || 100 < trGetN.x1.nVal ) { strErrMsg = "x1 is out of range. Must be from zero to 100."; bOKEnable = false; } else bOKEnable = true;
When an X-Function is being called programmatically and its dialog is not going to be shown, then you need another way to notify the user of any errors that may occur. Origin C has defined macros to output an error message to the Results Log, Command Window or Script Window. It is strongly recommended that you use these macros instead of out_str or printf.
The XF_WARN macros are used to output warning messages and do not terminate execution. All three macros accept a string as the first argument, containing the warning message. The two macros that accept additional arguments assume the warning message is also a format string for outputting one or two values.
// Assume the following: // #define MIN_DATA_POINTS 5 // int nNumPts = 3; // string strWksName = "Book1"; XF_WARN("Too few data points."); XF_WARN_EX("Number of data points less than %d.", MIN_DATA_POINTS); XF_WARN_EX("Worksheet named %s was not found.", strWksName); XF_WARN_EX2("Only %d data points, need at least %d.", nNumPts, MIN_DATA_POINTS);
The XF_TRACE macro is similar to the XF_WARN macros in that it does not terminate execution. It also takes a message for the first argument, but it allows any number of additional arguments.
// Assume the following: // #define MIN_DATA_POINTS 5 // int nNumPts = 3; // string strWksName = "Book1"; XF_TRACE("Only %d data points found in %s, need at least %d.", nNumPts, strWksName, MIN_DATA_POINTS);
The XF_THROW macros terminate execution, but everything else about them is the same as the XF_WARN macros. All three macros accept a string containing the warning message as the first argument. The two macros that accept additional arguments assume the warning message is also a format string for outputting one or two values.
// Assume the following: // #define MIN_DATA_POINTS 5 // int nNumPts = 3; // string strWksName = "Book1"; XF_THROW("Too few data points."); XF_THROW_EX("Number of data points less than %d.", MIN_DATA_POINTS); XF_THROW_EX("Worksheet named %s was not found.", strWksName); XF_THROW_EX2("Only %d data points, need at least %d.", nNumPts, MIN_DATA_POINTS);