When you write a GUI program you can divide the interface into two parts: how it appears and how it interacts with the program's "internals". In your code, for example, you may not think about the buttons order in any dialog box. GRAPE can place your dialogs, menus, buttons and cursors into separate modules which are written on GRAPE's original "script language", called ERC (the Eiffel Resource Code).
You can ask why we must learn another language? Please do not worry again, this language is very similar to our favorite Eiffel. If you know the Resource script language for Microsoft Windows you can easily understand ERC. If you have no experience in the Resource languages you can simply understand it if you know the Eiffel language. And more, if you are using our Interface Builder (IB) you can ignore ERC at all, simply draw your fantasies with it.
Now let's compare the code using the embedded menu creation calls and the code using the ERC resources.
This only a piece of code from the TEMPLATE directory. It builds the menu structure "manually".
make_menu : MENU is local menus : MENU; popup : SUB_MENU_ITEM; entry : MENU_ENTRY; item : MENU_ITEM; do !!Result.make_root; !!menus.make; !!item.make("&New child window", 0, IDM_NEW ); menus.add(item); !!entry.make_separator menus.add(entry); !!item.make("&Close", 0, IDM_CLOSE ); menus.add(item); !!item.make("Close Al&l childs", 0, IDM_CLOSE_ALL); menus.add(item); !!item.make("E&xit", 0, IDM_QUIT ); menus.add(item); !!popup.make("&File", 0, menus ); Result.add(popup); !!menus.make; !!item.make("&Cascade", 0, IDM_CASCADE ); menus.add(item); !!item.make("&Tile", 0, IDM_TILE ); menus.add(item); !!item.make("Arrange &Icons", 0, IDM_ARRANGE ); menus.add(item); !!popup.make("&Window", 0, menus ); Result.add(popup); end;
What a terrible code it is? And only imagine that you have to insert it in each your application. Fortunately it's not necessary if you use our ERC resources.
Start Interface Builder and create file RESOURCE.ERC into the TEMPLATE directory. Create a menu resource called MAIN_MENU and save it. You will got a "very pretty" ERC file:
menu MAIN_MENU is sub_menu is text := "&File"; menu_item is text := "&New child window"; command := IDM_NEW; checked := false; disabled := false; end; separator; menu_item is text := "&Close"; command := IDM_CLOSE; checked := false; disabled := false; end; menu_item is text := "Close A&ll childs"; command := IDM_CLOSE_ALL; checked := false; disabled := false; end; menu_item is text := "E&xit"; command := IDM_QUIT; checked := false; disabled := false; end; end; sub_menu is text := "&Window"; menu_item is text := "&Cascade"; command := IDM_CASCADE; checked := false; disabled := false; end; menu_item is text := "&Tile"; command := IDM_TILE; checked := false; disabled := false; end; menu_item is text := "Arrange &Items"; command := IDM_ARRANGE; checked := false; disabled := false; end; end; end;
Are you surprised? You see a typical Eiffel text? Of course, the idea of ERC is to simplify the resource definitions for GRAPE programmers. Another reason to make ERC is to unify the resource definitions for different platforms. You can simply port your programs from MS Windows to Mac and you will have no problems with the resources.
Next step is to compile the script into a separate module. For Windows we must create a Dynamic-Linked Library (DLL). Examine MAKEFILE for the commands you need to create it. DLL is created from the C-source stub and RC script. You can produce a Microsoft compatible resource file with Interface Builder if you use the "Save as RC" menu item.
The piece of code that builds the menu structure "manually" (see above) can be replaced by the following code if ERC is used:
make_menu () : MENU is local rc : RESOURCE_CONTAINER do !!rc.make rc.open("generic.dll") if rc.is_valid then !!Result.load(rc, MAIN_MENU); rc.close(); end end
And that's all!
The next problem is connected with menu item identifiers. When you save resources as the GENERIC.RC file Interface Builder automatically generates file GENERIC.E with class RESCONST in it. Use it instead of SYS_CMD.E (according to the tradition all constants used in GRAPE's applications such as menu item commands are placed into class SYSTEM_COMMAND), make the appropriate changes into file GENERIC.PDL and in the inheritance clause of the GEN_APPLICATION class. Now you can compile a new version of the GENERIC application.
This is the short form of the RESOURCE_CONTAINER class.
class RESOURCE_CONTAINER creation make feature -- System identifier of loaded binary resource sys_id : INTEGER; filename : STRING; make -- creation feature open ( file : STRING ) -- Tries to load platforms binary resource file -- (DLL for windows) close -- Frees previously loaded binary resource file is_valid : BOOLEAN -- Checks wether the load is successful load_string ( string_num : INTEGER ) : STRING -- Loads string by number from RC file end
You should work with this class in the following sequence:
make... open... if is_valid... load... load... close
If you want to load a resource (for example an icon) from the file you should call the load feature instead of make:
load (rc : RESOURCE_CONTAINER, code : INTEGER)
This feature is an alternative creation feature for classes RECT, TILE, BRUSH, COLOR, GRAPHICS_CURSOR, FONT, ICON, PEN, PICTURE. For more information about the resourceable objects, please look at the ERC On-Line Reference.
close
Use this feature with a special care. After the resource container has been closed all the resources loaded from it become unavailable. For example:
!!rc.make... rc.open... if rc.is_valid then !!ico.load (rc, MY_ICON) application.set_icon (ico) -- This is invalid!!! rc.close end
After you have closed the rc container the application will lose its icon.