Would you like to make this site your homepage? It's fast and easy...
Yes, Please make this my home page!
Writing New Tool Functions
The GUI Designer toolkit provides a very convenient method of including re-usable grid functions in your code. Once you are comfortable using GUI Designer to write your own grid functions, it is fairly easy to learn to create new tools that can be added to the toolkit and used just like the built-in tools. This page describes one approach to writing and using tool grid functions.
- The toolkit is the collection of tools made available in the PDE when the GUI Designer toolkit button is pressed.
- A tool is a grid function defined in a toolset, containing all of the code necessary to create and operate the grid.
- A toolset is an XBasic GUI Designer program containing one or more tools, compiled as a dynamic library (DLL). Toolsets created by a programmer are sometimes called accessory toolsets, to distinguish them from the standard toolset containing tools defined in the GUI Designer ("xui") library.
- The master toolkit file (templates\xtoolkit.xxx) contains a list of toolset text files.
- Each toolset text file (eg., xtool0.xxx) lists tools to be included in the toolkit. It may include tools from more than one toolset.
Creating an accessory toolset involves the following steps:
- Create a GUI Designer program (the toolset) to contain the tools.
- Write a grid function for each tool to be included in the toolset.
- Compile the toolset source code to create the toolset DLL.
- Create a toolset text file listing the tools in the toolset.
- Add the name of the toolset text file to the master toolkit file.
The example below illustrates this procedure, by developing a simple scrollable grid for displaying BMP-format images. The complete source code for this example can be viewed here
1. Create the toolset source program.
The source program for a toolset is a GUI Designer program, created in the usual way - select 'new' from the XBasic PDE file menu, then click the 'gui program' button. The PROLOG can be edited immediately, paying attention to the following:
- The program name must be set in the PROGRAM statement, and must be the same as the program file name. This example will be called 'tooldemo.x', so the PROLOG should contain the statement: PROGRAM "tooldemo"
- The Entry() function is, by default, declared as an INTERNAL FUNCTION; this must be changed to DECLARE FUNCTION. Also, the Entry() function must be exported:
DECLARE FUNCTION Entry ()
- In an ordinary XBasic program, the entry function can be given any name, as long as it is the first function declared in the PROLOG. In a program intended to be compiled as a toolset DLL, however, the name must remain Entry().
For testing purposes, it is convenient to create a test window, using the GUI Designer toolkit, containing an XuiLabel grid as a placeholder for the new tool. Use the Appearance Window's 'Image' option to select a large BMP-format image to be displayed in the grid. If the program is run at this point, the image should be displayed in the label grid, but of course without scroll bars.
2. Write the grid function for the tool.
The appearance of the tool is laid out in the usual way, using the PDE's toolkit to create the desired grid. In this example, create a window called ScrollImage, and place into it XuiLabel, XuiScrollBarV, and XuiScrollBarH grids, which will be the kids of the new grid. Size and position the grids as desired, name them (eg., ImageGrid, ScrollV, ScrollH), and select styles, borders, etc., using the Appearance window. Then use Window, ToFunction to create the grid function ScrollImage(), and the callback function ScrollImageCode().
Callbacks ultimately need to be handled by the tool's grid function; it is easiest to do this from the start, so delete the callback (aka 'code') function - you won't be using it.
Now is a good time to take care of a few details elsewhere in the program, before proceeding to flesh out the grid function:
- In the PROLOG, change INTERNAL FUNCTION ScrollImage() to DECLARE FUNCTION, and put it into the EXPORT...END EXPORT block after the Entry() function.
- Remove all of the code relating ScrollImage() from FUNCTION CreateWindows(). The program that uses the tool will take care of creating the window.
- In FUNCTION InitProgram(), include a statement to initialize the grid function. Just put in a call to the function, with all parameters set to zero:
ScrollImage (0, 0, 0, 0, 0, 0, 0, 0)
Failure to do this will mean that the PDE will be unable to load the tool into the toolkit.
Now that there is a basic grid function for the tool, go to the grid function for the test window, SUB Create, and change the line
XuiLabel (@g, #Create, ....
ScrollImage (@g, #Create, ....
Run the program, and the test window should display the label with scroll bars. But there is no image, and the scroll bars do nothing, because the grid function contains no code to process the relevant messages. Several changes need to be made in SUB Initialize, in the tool's grid function, so that the function will handle messages appropriately.
- Callbacks will be handled within the grid function, so comment out
func[#Callback] = &XuiCallback()
and remove the comment from
sub[#Callback] = SUBADDRESS (Callback)
- The tool will probably need to be resizable, so remove comments from
func[#GetSmallestSize] = 0
func[#Resize] = 0
sub[#GetSmallestSize] = SUBADDRESS (GetSmallestSize)
sub[#Resize] = SUBADDRESS (Resize)
and comment out
XuiSetGridTypeProperty (gridType, @"maxWidth", designWidth)
XuiSetGridTypeProperty (gridType, @"maxHeight", designHeight)
XuiSetGridTypeProperty (gridType, @"minWidth", designWidth)
XuiSetGridTypeProperty (gridType, @"minHeight", designHeight)
The tool will probably need to respond to one or more messages in order to operate properly. In the example, to display the image, the grid function will need a "SUB SetImage" to process the #SetImage message; and also a "SUB Scroll" to process #Change, #OneMore, #OneLess, #MuchMore, and #MuchLess messages. The addresses of these SUBs should be added to the list in SUB Initialize:
sub[#SetImage] = SUBADDRESS(SetImage)
sub[#Change] = SUBADDRESS(Scroll)
sub[#OneLess] = SUBADDRESS(Scroll)
sub[#OneMore] = SUBADDRESS(Scroll)
sub[#MuchLess] = SUBADDRESS(Scroll)
sub[#MuchMore] = SUBADDRESS(Scroll)
(To be complete, the example should also repond to #SetImageCoords, #GetImage, and #GetImageCoords, and probably #MouseWheel; these are ignored here to keep things simple.)
Now write the SUBs that actually operate the tool. The SUBs will differ depending on the tool's function - see the source code
for the SUBs required by the ScrollImage example. There are no particular difficulties in writing these SUBs, assuming you are familiar with ordinary GUI Designer programs, but there is one point to keep in mind. In any program that uses the tool, there may be several instances of the tool active at once, all using the same grid function. The function must be written so that the different instances do not interfere with each other. Mainly, this means that STATIC and SHARED variables should be used only
for quantities that apply to all active instances - quantities specific to each instance should be kept in a value array, from which they can be retrieved as needed. #SetValue, #GetValue, and related messages are useful here. Since each instance of the tool will have its own value array, there is no interference between instances. In the ScrollImage example, the image grid number, and the width and height of the image, are kept in a value array for this reason.
3. Compile the toolset source.
The toolset is compiled as an ordinary DLL, selecting 'library' from the PDE's 'run' menu. See Making a Standalone Executable
for more information. You can remove the code associated with the test window once the tool has been tested, but there is no harm in leaving it in. Because of a bug in the PDE, you may see a compile-time error like "0x00000000 undefined". Just convert the file to text mode (select 'mode' from the file menu), then convert back to program mode and try compiling again.
4. Create the toolset text file.
The toolset text file can be created with any text editor. The fields in each entry in the file are
dllname gridType gridFunc imageFile category
Each entry must start with one or more tabs, and fields must be tab-separated. Consult the standard toolset text file, xtool0.xxx (in the XBasic\templates folder) for examples of the proper format.
dllname is the name of the toolset dll, without the .dll extension. This DLL must be somewhere in the Windows search path, such as the \Windows folder or the XBasic\bin folder.
gridType is the name under which the tool function's grid type was registered (this happens in the grid function, SUB Initialize, in the call to XuiRegisterGridType()). The gridType is always the same as the gridFunc.
gridFunc is the name of the grid function that defines the tool.
is the name of a 32x32-pixel BMP-format file. It must be in the XBasic\images folder, and can be 16, 256, or 24-bit color. A suitable image for the ScrollImage tool can be downloaded here
- save it in your XBasic\images folder.
category is a general category name for the tool (Button, List, etc.). This field is never used, so any category name is acceptable.
tooldemo ScrollImage ScrollImage scrollimage.bmp Image
Once all tools are listed in the toolset text file, save it in the XBasic\templates folder.
5. Add the toolset text file name to the master toolkit file.
This file is called xtoolkit.xxx, and is located in the XBasic\templates folder. It consists simply of a list of names of toolset text files. Do not include a path for any of the listed files. Any file name can be commented out, using the usual XBasic comment character ('). In fact, any file name in xtoolkit.xxx that does not begin with a letter of the alphabet will be ignored.
Using the new tool.
If everything has been done properly, it should now be possible to start up the PDE, create a GUI program shell, click the toolkit button, and find a new button corresponding to the ScrollImage tool. The tool can be used like any of the built-in tools, keeping in mind a couple of points:
- The program that uses the tool must IMPORT the toolset DLL. In the ScrollImage example, IMPORT "tooldemo" must appear in the PROLOG, and tooldemo.dll must be distributed along with the program for it to run properly. It is possible also to link the object file tooldemo.o statically to the EXE, so that tooldemo.dll is not needed. See Modular Programming for more information, and be sure to read the part about the Entry function. The Entry function in any GUI Designer module performs vital initialization; it is not called automatically when the module is statically linked, so the calling program must do this explicitly.
- If multiple instances of the tool are created in the same grid, GUI Designer gives them all the same grid name; unlike built-in tools, there is no distinguishing number (like XuiLabel737, for example) added to the end of the name. It will be necessary to use the toolkit Appearance Window to manually enter a distinct name for each grid.