INSTRUCTIONS FOR RESOURCE TO C CODE CONVERTER V1.2 (RTCCCH.PRG) Machine: Atari ST/TT range Resolution: ST-Low, ST-Med, ST-High, TT-Low, TT-Med, TT-High Memory: 512K Hello fellow ATARI ST programmers, This utility program converts any standard ST resource file into a C code file, which can be easily imported into your own C programs. It effectively performs the error prone task of hard-coding your resource files. Naturally, this program requires the use of a resource construction set (RCS) and an implementation of the C language. It has been specifically designed to work with the Lattice C V5 Development System, produced by HiSoft. I will assume, that you have some elementary knowledge of object trees and resource files, but if you don't, there are a number of books on the subject. Why hard-code resources? If you look at your collection of GEM software, the chances are that most of them will make use of an external resource file which is stored in the same directory. However, once in a while you'll come across a program that uses menus and dialog boxes, but there isn't a resource file to be found anywhere. In this case, the resources have been hard- coded into the program. There are advantages to both methods and it depends really on the preference of the programmer. The classic argument for keeping resources external, is that you can make limited changes to the resources without recompiling the source code. Thus, if the program makes extensive use of a resource file, the program can be translated into a different language, without having to refer back to the source code. However, these changes are severely limited, as the structure of the resource has to be preserved. No objects may be added or deleted and only their contents, size and location may be changed. On the other hand, if the resources are included in the source file, they become human readable, can easily be printed for a permanent record and are far easier to document. Small changes can be made from the editor, but is only recommended if you know what you are doing. The RTCCCH program automatically assigns each structure occurrence a unique identifier, so they can be directly accessed without the use of indirection. For example, if you wished to access an input field in a form, you can directly access the string in the appropriate occurrence of the TEDINFO structure. No longer will you have to find the address of the structure through the ob_spec field of the object. In my opinion, this makes programming with resources much easier, especially for beginning GEM programmers. The third reason is that resources may now be optimized. For example, a form contains two similar bit images, which are duplicated in the object tree. Space could be saved if the only the first occurrence of the bit image is kept and the pointer to the now 'missing' bit-image is redirected to the first image. The fourth reason, perhaps the most important reason where the C language is concerned, resources can now be local to files and functions. C is a structured language, in which a function's data is local and hidden from other functions and modules, this concept can be extended to resources as well. In a huge project, where hundreds of functions are scattered across a dozen or so files, local resources are far easier to manage than one large resource file. Local resources also enable the creation of stand-alone C libraries that use resources. If your program is to run in more than one resolution, you may have to use more than one resource file. The resolution in which RTCCCH.PRG is executed DOES affect the resulting code file. The program loads the resource using the rsrc_load() function, which automatically makes adjustments to the coordinates to conform to the current resolution. So remember to run RTCCCH.PRG in the resolution in which the resource is to be used. There are basically two ways to deal with the resolution problem, one is to have access to several version of the same resource, or to write a piece of code which alters the object tree as required. What I recommend, is that you create several versions of the resource file using your RCS and then convert them all and then compare them. That is what I have done when I wrote RTCCCH. Let experience is your tutor. How to use RTCCCH.PRG When running RTCCCH.PRG, you are presented with a dialog that handles every function of the program. The Input File field should contain the name for the resource file which is to be converted. The Output File field should contain the name of the resultant C code file. The two 'Ask' buttons call up the file selector for the respective fields. You may not always wish to convert the whole resource file, thus you can specify a range of trees to convert. The first tree has an index of zero, the second and index of 1 and so on. The default indexes of are set to zero, so only the first object tree is converted. When dealing with a huge object tree, it is quite difficult to determine the index of a particular object (unless you want to refer to the header file produced by the RCS), therefore RTCCCH.PRG gives you the option of including the index number in front of every object in comments. You also have the option of producing external declarations only, which is useful if the actual object tree is to be located in another module. The 'OK' button will perform the conversion and the 'Exit' button quits the program. Some care must be taken when this program is run. The input file should be a standard resource file and the indexes of the object trees to be converted must be a valid range, otherwise the program may produce unpredictable results. WARNING: The output file produced will OVERWRITE an existing file. A C code object tree will consist of several occurrences of structures followed by an array of objects. The objects in the array will be linked to each other using indexes (short integers) and may be linked to a structure using a label. A label is generated as follows: The name of the type of the object is followed by the tree index. Structures other than the object tree will be followed by an underline symbol and the object index number. This is to ensure that there are no duplicate labels, while still being reasonably readable. NOTE: If a object tree should use ProgDefs, a reference label is set up as outlined before, but it is left up to the programmer to define. Following is an example of how to effectively use this program. We are going to write a program, that displays a dialog box with a bit image of a smiling face, two strings 'Are you' and 'happy?' and a 'Yes' and 'No' button, all within a border. Below is an approximation of how it is going to look like. ------------------- | ------ | (Diagram not to scale - | | O O | | In reality the bit image | | | Are You | will be much smaller) | | | | | happy? | | | -- | | | ------ | | | | ----- ---- | | | Yes | | No | | | ----- ---- | ------------------- The first step is to load a resource construction set and create this dialog box and save it to disk, say under the name 'DIALOG1.RSC'. Any other files the RCS may produce are unnecessary. The next step is to load up RTCCCH. The resource name and C code should be set to 'DIALOG1.RSC' and 'DIALOG1.C', respectively. Remember, that you may use full path names with drive letters. Alternatively, press the 'Ask' buttons to use the file selector. Because there is only one object tree in the file, the indexes should be left as they are. Then simply press the 'OK' button. A message should come up to tell you that the resource has been successfully converted and you are returned to the dialog. Simply press the 'Exit' button to quit the program. The above instruction should produce a file that look something like this: short bi_pdata0_1[] = { 0x0000,0x03C0,0x0C30,0x1008,0x2004,0x2664,0x4662,0x4002,0x4002,0x4002, 0x2424,0x23C4,0x1008,0x0C30,0x03C0,0x0000 }; BITBLK bitblk1 = { bi_pdata1, 2, 16, 0, 0, 1 }; OBJECT object_tree0[] = { -1, 1, 5,G_BOX, 0x0000,0x0000,(void *)0x021181,16,16,152,96, 2,-1,-1,G_IMAGE, 0x0000,0x0000,(void *)&bitblk0_1,16,16,16,16, 3,-1,-1,G_STRING,0x0000,0x0000,(void *)"Are you",56,16,56,16, 4,-1,-1,G_STRING,0x0000,0x0000,(void *)"happy?",56,32,48,16, 5,-1,-1,G_BUTTON,0x0005,0x0000,(void *)" Yes ",16,64,56,16, 0,-1,-1,G_BUTTON,0x0025,0x0000,(void *)" No ",88,64,48,16 }; Once we give the object trees some sensible names, you are ready to write the program to handle the object tree. The full program is below. #include short happy_image[] = { 0x0000,0x03C0,0x0C30,0x1008,0x2004,0x2664,0x4662,0x4002,0x4002,0x4002, 0x2424,0x23C4,0x1008,0x0C30,0x03C0,0x0000 }; BITBLK happy_block = { happy_image, 2, 16, 0, 0, 1 }; OBJECT ask_if_happy[] = { -1, 1, 5,G_BOX, 0x0000,0x0000,(void *)0x021181,16,16,152,96, 2,-1,-1,G_IMAGE, 0x0000,0x0000,(void *)&happy_block,16,16,16,16, 3,-1,-1,G_STRING,0x0000,0x0000,(void *)"Are you",56,16,56,16, 4,-1,-1,G_STRING,0x0000,0x0000,(void *)"happy?",56,32,48,16, 5,-1,-1,G_BUTTON,0x0005,0x0000,(void *)" Yes ",16,64,56,16, 0,-1,-1,G_BUTTON,0x0025,0x0000,(void *)" No ",88,64,48,16 }; int main(void) { short x, y, w, h; /* initialize the application */ appl_init(); /* center the dialog box */ form_center(ask_if_happy, &x, &y, &w, &h); /* reserve the necessary workspace */ form_dial(FMD_START, 0, 0, 0, 0, x, y, w, h); form_dial(FMD_GROW, 0, 0, 0, 0, x, y, w, h); /* draw the dialog box */ objc_draw(ask_if_happy, ROOT, MAX_DEPTH, x, y, w, h); /* handle dialog box */ form_do(ask_if_happy, 0); /* remove the dialog box and return the workspace */ form_dial(FMD_SHRINK, 0, 0, 0, 0, x, y, w, h); form_dial(FMD_FINISH, 0, 0, 0, 0, x, y, w, h); /* terminate the application */ appl_exit(); /* return to calling program */ return 0; } That's all there is to it. Why don't you try lifting the above section out of this file, compile and run it. Menus are handled much in the same fashion, but you use the menu_bar() function to display the menu bar and use either evnt_mesag() or evnt_multi() to use them. Below is a rough skeleton of what you are expected to do. #include ... OBJECT menu[] = \ { ... | This is the output of RTCCCH.PRG ... | }; / int main(void) { short message[8]; /* initialize the application */ appl_init(); /* install the menu */ menu_bar(menu, 1); /* wait for a menu event */ do { evnt_mesag(message); } while (message[0] != MN_SELECTED); /* deinstall the menu */ menu_bar(menu, 0); /* terminate the application */ appl_exit(); return 0; } If you have any problems with this program or have some ideas on how to improve it, do not hesitate to contact me. Arnd Hurlbrink 8 Mahonia Place Duncraig WA 6023 West Australia Watch out for an assembler version of this program sometime in the future. Well, that's all from me for now. Happy programming! Written 04/11/91 Updated 20/02/92 End Of File