User Tools

Site Tools


This is an old revision of the document!


GUI Files Explained

FIXME This page is currently work in progress.

Each GUI comprises several files on disk, such as the GUI scripts, material definition files, and texture images.

GUI files can be created with the GUI Editor, written by hand, or a combination of those:

  • The GUI Editor allows users to define and design the contents and layout of the windows that compose a GUI. However, the work in the GUI Editor is focused mainly on static aspects like window position and size, texts, colors, borders, etc.
  • Everything “dynamic” and all sorts of effects can, by their nature, not be added by means of the GUI Editor, but must be written as custom, hand-crafted script code that augments the script that is auto-generated by the GUI Editor each time the “static” part of the GUI is saved.

One key question addressed in this section is how we can combine hand-crafted script code and editor-edited script code, while keeping both separated so that they don't overwrite each other.

In general, when you save a GUI in the GUI Editor, the editor creates or re-creates some of the files it is composed of, updates others, and leaves alone the rest. The result is normally exactly what you want and expect, but sometimes you may wish to or must hand-tune the details (such as the GUI scripts or material definitions) without and independently of the GUI Editor. In such cases, it is very helpful to understand the files that belong to a GUI.

This section explains the files that together form a GUI, how they relate to each other, and how hand-crafted and editor-created scripts can peacefully coexist.

One directory per GUI

cgui GUI definition files

cmat material definition files

Texture images

Augmenting GUI Editor scripts with custom script code

Assume that you're using the GUI Editor in order to create a “Call Lift” GUI. Let's also assume that when done, you want to access your new GUI under the file name CallLift.cgui.

The trick is that when you save this GUI in the GUI Editor, you'd not save it under file name CallLift.cgui. Instead, you save it under file name CallLift_init.cgui. Next, create a second file next to CallLift_init.cgui with the name that you actually want, CallLift.cgui.

The new CallLift.cgui file will be the file that you actually use, and it will contain all hand-written custom code. For this to work, it must include the GUI Editor created file, and therefore its content looks like this:

dofile("Games/DeathMatch/GUIs/CallLift_init.cgui");    -- Include the GUI Editor generated file.
 
-- Add your hand-written custom code below this line.
-- ...

In summary:

  • When you edit your GUI in the GUI Editor, you only load and save file CallLift_init.cgui.
  • All hand-written code enters file CallLift.cgui instead.
  • The connection between the two files is made by the dofile() command.


Tip by the Cafu development team:
The Games/DeathMatch/GUIs/MainMenu/MainMenu(_init).cgui files that are natively included with Cafu are prime examples of this technique.

Future versions of the GUI Editor may even mildly enforce the two-files approach, where one file has the normal file name and its “twin” gets the _init suffix automatically appended. This helps e.g. to prevent accidental overwrites when you happen to load CallLift.cgui into the GUI Editor instead of CallLift_init.cgui.

Definition of GUIs: The cgui File Format

For each GUI that occurs in Cafu, its definition is stored in a .cgui file. As many other Cafu related files (e.g. .cmat material definition files), these files are simple ASCII text files. Therefore, you can not only conveniently create them with the GUI Editor, but you can also edit or write them by hand, if necessary even from scratch.

The ability to edit GUIs in a text editor and the understanding of the related .cgui file format can be crucial. For example, at the time of writing this text, no graphical GUI Editor existed, and all early Cafu GUIs therefore had to be written by hand. It comes also in helpful if you ever come across a GUI that for some reasons doesn't work well or not at all with the GUI Editor. More importantly, if you just want to make a few quick changes or fixes to a GUI, editing the .cgui files directly can be a lot faster and more convenient than using the GUI Editor.

reallyquit.jpg

General structure

The most important insight is that each GUI is in fact a hierarchy of windows, just like a program dialog of a real OS. Each window is basically just a rectangle with certain properties, like position, size, border color and thickness, text to display, etc.

However, the most important statements that we have to provide in order to instantiate a new window are its class (or type), and its name.

The class of a window determines the most crucial features of the window, e.g. if it displays text, if the user can enter text, if it shows a value as a slider control, if it presents a list of items to select from, etc. Section window_classes shows a list of all available window classes, however the most commonly used window class is just windowClass, which provides you with an all-purpose window with basic capabilities.

The name of a window must be unique throughout the entire GUI – no other window must have the same name. This is important because both scripts and engine code may refer to windows by name, and things tend to become very confusing if two or more windows have a name in common.

How cgui files are loaded

When a new Lua program for a GUI is created, it is initially empty. During initialization, the GuiSys then adds several Lua tables to the empty program in order to provide the subsequent script code something to work with. Note that in Lua, tables are very general and very powerful, and they are used to express several independent concepts. For example, the functions of a library are all kept in a common table, or object-oriented programming behaviour is simulated by considering a table as an object, where the table entries correspond to member variables and member functions (methods). Several examples for these cases are included below, however you should also study the relevant concepts in the Lua documentation, e.g. online at http://www.lua.org/pil/11.html.

Only after the empty Lua program for a GUI has been initialized with several tables is the code from all the script blocks concatenated to the program and the initialization complete. More precisely, the initialization consists of the following steps:

  1. Most of the Lua Standard Libraries are loaded, namely the basic, package, table, io, os, string and math libraries. Please refer to the Lua documentation for details, online resources are at http://www.lua.org/pil/18.html and http://www.lua.org/manual/5.1/manual.html#5. With these libraries, you can for example use expressions like
        a = math.sin(3.1415926);

    in your scripts.

  2. The Cafu Console library is loaded. This is a table with name Console that in fact provides an interface to the internal Cafu console. Please see the reference documentation at console for details. Example use:
        Console.Print("Hello!\n");
  3. The Cafu command manager library is loaded. This is a table with name ccm that provides access to the related Cafu interface. Please see the reference documentation at ccm for details. Example use:
        Command="show";
        ccm.ExecuteCommand("list " .. Command);
  4. Meta-tables for GUIs and GUI windows are created. They are used with the GUI and window objects below, and are not intended for direct use by the scripts.
  5. The global variable gui is added. The gui variable is in fact a table that represents the GUI object itself. It has methods that are relevant not for an individual window of the GUI, but for the entire GUI. See gui for details. Example use:
        gui:setFocus(ConsoleInput);
        gui:close();
  6. Most importantly, for each window in the GUI, a table with the name of the window is created that represents that very window. In the above example, window objects (tables) with the names Background, ReallyQuit, ButtonYes and ButtonNo are created. Contrary to the above tables however, you're not just supposed to access and call existing, predefined methods and variables, but you can (and in fact should) provide your own! Typical example for a frames-per-second window with name FPS:
        FPS.oldTime=FPS:get("time");
     
        function FPS:OnInit()
            -- ...
        end
     
        function FPS:OnFrame()
            local newTime=FPS:get("time");
            local deltaTime=newTime-self.oldTime;
     
            if (deltaTime<0.000000001) then
                self:set("text", string.format("FPS\nINF\n(%.4f sec)", deltaTime));
            else
                self:set("text", string.format("FPS\n%.2f\n(%.4f sec)", 1/deltaTime, deltaTime));
            end
     
            FPS.oldTime=newTime;
        end

    For a list of the predefined methods of each window that are available to you (e.g. the set() and get() methods above), please refer to section predefined_methods. For a list of methods that the GuiSys expects you to override for customization (e.g. the OnInit() method above), please refer to section called_methods.

  7. The final step is the addition of the contents of all the script { … } blocks. The scripts may now access and use all of the above mentioned variables/tables/objects/interfaces, and in fact they often look very much like the example snippet that I provided in the previous step.

Only after these steps is the initialization of a GUI script complete. The GuiSys then compiles each script and calls the OnInit() method for each window. That is, in the above example, it calls the methods Background:OnInit(), ReallyQuit:OnInit(), ButtonYes:OnInit() and ButtonNo:OnInit(). (Only if definitions have been provided in the script, of course. Otherwise, the corresponding call is just skipped.)

guisys/guifiles.1308822745.txt.gz · Last modified: 2013-01-07 12:07 (external edit)