ui_nodes.c

Go to the documentation of this file.
00001 
00005 /*
00006 Copyright (C) 2002-2010 UFO: Alien Invasion.
00007 
00008 This program is free software; you can redistribute it and/or
00009 modify it under the terms of the GNU General Public License
00010 as published by the Free Software Foundation; either version 2
00011 of the License, or (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016 
00017 See the GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this program; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00023 */
00024 
00025 #include "ui_main.h"
00026 #include "ui_internal.h"
00027 #include "ui_nodes.h"
00028 #include "ui_parse.h"
00029 #include "ui_input.h"
00030 
00031 #include "node/ui_node_abstractnode.h"
00032 #include "node/ui_node_abstractscrollbar.h"
00033 #include "node/ui_node_abstractoption.h"
00034 #include "node/ui_node_abstractvalue.h"
00035 #include "node/ui_node_bar.h"
00036 #include "node/ui_node_base.h"
00037 #include "node/ui_node_baseinventory.h"
00038 #include "node/ui_node_button.h"
00039 #include "node/ui_node_checkbox.h"
00040 #include "node/ui_node_controls.h"
00041 #include "node/ui_node_video.h"
00042 #include "node/ui_node_container.h"
00043 #include "node/ui_node_custombutton.h"
00044 #include "node/ui_node_editor.h"
00045 #include "node/ui_node_ekg.h"
00046 #include "node/ui_node_image.h"
00047 #include "node/ui_node_item.h"
00048 #include "node/ui_node_linechart.h"
00049 #include "node/ui_node_map.h"
00050 #include "node/ui_node_material_editor.h"
00051 #include "node/ui_node_messagelist.h"
00052 #include "node/ui_node_model.h"
00053 #include "node/ui_node_option.h"
00054 #include "node/ui_node_optionlist.h"
00055 #include "node/ui_node_optiontree.h"
00056 #include "node/ui_node_panel.h"
00057 #include "node/ui_node_radar.h"
00058 #include "node/ui_node_radiobutton.h"
00059 #include "node/ui_node_rows.h"
00060 #include "node/ui_node_selectbox.h"
00061 #include "node/ui_node_sequence.h"
00062 #include "node/ui_node_string.h"
00063 #include "node/ui_node_special.h"
00064 #include "node/ui_node_spinner.h"
00065 #include "node/ui_node_tab.h"
00066 #include "node/ui_node_tbar.h"
00067 #include "node/ui_node_text.h"
00068 #include "node/ui_node_text2.h"
00069 #include "node/ui_node_textlist.h"
00070 #include "node/ui_node_textentry.h"
00071 #include "node/ui_node_keybinding.h"
00072 #include "node/ui_node_todo.h"
00073 #include "node/ui_node_vscrollbar.h"
00074 #include "node/ui_node_zone.h"
00075 
00076 typedef void (*registerFunction_t)(uiBehaviour_t *node);
00077 
00082 static const registerFunction_t registerFunctions[] = {
00083     UI_RegisterNullNode,
00084     UI_RegisterAbstractBaseNode,
00085     UI_RegisterAbstractNode,
00086     UI_RegisterAbstractOptionNode,
00087     UI_RegisterAbstractScrollableNode,
00088     UI_RegisterAbstractScrollbarNode,
00089     UI_RegisterAbstractValueNode,
00090     UI_RegisterBarNode,
00091     UI_RegisterBaseInventoryNode,
00092     UI_RegisterBaseLayoutNode,
00093     UI_RegisterBaseMapNode,
00094     UI_RegisterButtonNode,
00095     UI_RegisterCheckBoxNode,
00096     UI_RegisterConFuncNode,
00097     UI_RegisterContainerNode,
00098     UI_RegisterControlsNode,
00099     UI_RegisterCustomButtonNode,
00100     UI_RegisterCvarFuncNode,
00101     UI_RegisterEditorNode,
00102     UI_RegisterEKGNode,
00103     UI_RegisterFuncNode,
00104     UI_RegisterImageNode,
00105     UI_RegisterItemNode,
00106     UI_RegisterKeyBindingNode,
00107     UI_RegisterLineChartNode,
00108     UI_RegisterMapNode,
00109     UI_RegisterMaterialEditorNode,
00110     UI_RegisterMessageListNode,
00111     UI_RegisterModelNode,
00112     UI_RegisterOptionNode,
00113     UI_RegisterOptionListNode,
00114     UI_RegisterOptionTreeNode,
00115     UI_RegisterPanelNode,
00116     UI_RegisterRadarNode,
00117     UI_RegisterRadioButtonNode,
00118     UI_RegisterRowsNode,
00119     UI_RegisterSelectBoxNode,
00120     UI_RegisterSequenceNode,
00121     UI_RegisterSpecialNode,
00122     UI_RegisterSpinnerNode,
00123     UI_RegisterStringNode,
00124     UI_RegisterTabNode,
00125     UI_RegisterTBarNode,
00126     UI_RegisterTextNode,
00127     UI_RegisterText2Node,
00128     UI_RegisterTextEntryNode,
00129     UI_RegisterTextListNode,
00130     UI_RegisterTodoNode,
00131     UI_RegisterVideoNode,
00132     UI_RegisterVScrollbarNode,
00133     UI_RegisterWindowNode,
00134     UI_RegisterZoneNode
00135 };
00136 #define NUMBER_OF_BEHAVIOURS lengthof(registerFunctions)
00137 
00141 static uiBehaviour_t nodeBehaviourList[NUMBER_OF_BEHAVIOURS];
00142 
00149 const value_t *UI_GetPropertyFromBehaviour (const uiBehaviour_t *behaviour, const char* name)
00150 {
00151     for (; behaviour; behaviour = behaviour->super) {
00152         const value_t *result;
00153         if (behaviour->properties == NULL)
00154             continue;
00155         result = UI_FindPropertyByName(behaviour->properties, name);
00156         if (result)
00157             return result;
00158     }
00159     return NULL;
00160 }
00161 
00167 qboolean UI_CheckVisibility (uiNode_t *node)
00168 {
00169     uiCallContext_t context;
00170     if (!node->visibilityCondition)
00171         return qtrue;
00172     context.source = node;
00173     context.useCmdParam = qfalse;
00174     return UI_GetBooleanFromExpression(node->visibilityCondition, &context);
00175 }
00176 
00182 const char* UI_GetPath (const uiNode_t* node)
00183 {
00184     static char result[MAX_VAR];
00185     const uiNode_t* nodes[8];
00186     int i = 0;
00187 
00188     while (node) {
00189         assert(i < 8);
00190         nodes[i] = node;
00191         node = node->parent;
00192         i++;
00193     }
00194 
00196     result[0] = '\0';
00197     while (i) {
00198         i--;
00199         Q_strcat(result, nodes[i]->name, sizeof(result));
00200         if (i > 0)
00201             Q_strcat(result, ".", sizeof(result));
00202     }
00203 
00204     return result;
00205 }
00206 
00222 void UI_ReadNodePath (const char* path, const uiNode_t *relativeNode, uiNode_t **resultNode, const value_t **resultProperty)
00223 {
00224     char name[MAX_VAR];
00225     uiNode_t* node = NULL;
00226     const char* nextName;
00227     char nextCommand = '^';
00228 
00229     *resultNode = NULL;
00230     if (resultProperty)
00231         *resultProperty = NULL;
00232 
00233     nextName = path;
00234     while (nextName && nextName[0] != '\0') {
00235         const char* begin = nextName;
00236         char command = nextCommand;
00237         nextName = strpbrk(begin, ".@#");
00238         if (!nextName) {
00239             Q_strncpyz(name, begin, sizeof(name));
00240             nextCommand = '\0';
00241         } else {
00242             assert(nextName - begin + 1 <= sizeof(name));
00243             Q_strncpyz(name, begin, nextName - begin + 1);
00244             nextCommand = *nextName;
00245             nextName++;
00246         }
00247 
00248         switch (command) {
00249         case '^':   /* first string */
00250             if (!strcmp(name, "this")) {
00251                 if (relativeNode == NULL)
00252                     return;
00254                 node = *(uiNode_t**) ((void*)&relativeNode);
00255             } else if (!strcmp(name, "parent")) {
00256                 if (relativeNode == NULL)
00257                     return;
00258                 node = relativeNode->parent;
00259             } else if (!strcmp(name, "root")) {
00260                 if (relativeNode == NULL)
00261                     return;
00262                 node = relativeNode->root;
00263             } else
00264                 node = UI_GetWindow(name);
00265             break;
00266         case '.':   /* child node */
00267             if (!strcmp(name, "parent"))
00268                 node = node->parent;
00269             else if (!strcmp(name, "root"))
00270                 node = node->root;
00271             else
00272                 node = UI_GetNode(node, name);
00273             break;
00274         case '#':   /* window index */
00276             assert(node->behaviour == ui_windowBehaviour);
00277             node = UI_WindowNodeGetIndexedChild(node, name);
00278             break;
00279         case '@':   /* property */
00280             assert(nextCommand == '\0');
00281             *resultProperty = UI_GetPropertyFromBehaviour(node->behaviour, name);
00282             *resultNode = node;
00283             return;
00284         }
00285 
00286         if (!node)
00287             return;
00288     }
00289 
00290     *resultNode = node;
00291     return;
00292 }
00293 
00304 uiNode_t* UI_GetNodeByPath (const char* path)
00305 {
00306     uiNode_t* node = NULL;
00307     const value_t *property;
00308     UI_ReadNodePath(path, NULL, &node, &property);
00310     return node;
00311 }
00312 
00321 static uiNode_t* UI_AllocNodeWithoutNew (const char* name, const char* type, qboolean isDynamic)
00322 {
00323     uiNode_t* node;
00324     uiBehaviour_t *behaviour;
00325     int nodeSize;
00326 
00327     behaviour = UI_GetNodeBehaviour(type);
00328     if (behaviour == NULL)
00329         Com_Error(ERR_FATAL, "UI_AllocNodeWithoutNew: Node behaviour '%s' doesn't exist", type);
00330 
00331     nodeSize = sizeof(*node) + behaviour->extraDataSize;
00332 
00333     if (!isDynamic) {
00334         if (ui_global.curadata + nodeSize > ui_global.adata + ui_global.adataize)
00335             Com_Error(ERR_FATAL, "UI_AllocNodeWithoutNew: No more memory to allocate a new node");
00336         node = (uiNode_t*) ui_global.curadata;
00338         ui_global.curadata = ALIGN_PTR(ui_global.curadata, 8);
00339         ui_global.curadata += nodeSize;
00340         ui_global.numNodes++;
00341         memset(node, 0, nodeSize);
00342     } else {
00343         node = (uiNode_t*)Mem_PoolAlloc(nodeSize, ui_dynPool, 0);
00344         memset(node, 0, nodeSize);
00345         node->dynamic = qtrue;
00346     }
00347 
00348     node->behaviour = behaviour;
00349 #ifdef DEBUG
00350     node->behaviour->count++;
00351 #endif
00352     if (node->behaviour->isAbstract)
00353         Com_Error(ERR_FATAL, "UI_AllocNodeWithoutNew: Node behavior '%s' is abstract. We can't instantiate it.", type);
00354 
00355     if (name != NULL) {
00356         Q_strncpyz(node->name, name, sizeof(node->name));
00357         if (strlen(node->name) != strlen(name))
00358             Com_Printf("UI_AllocNodeWithoutNew: Node name \"%s\" truncated. New name is \"%s\"\n", name, node->name);
00359     }
00360 
00361     /* initialize default properties */
00362     if (node->behaviour->loading)
00363         node->behaviour->loading(node);
00364 
00365     return node;
00366 }
00367 
00376 uiNode_t* UI_AllocNode (const char* name, const char* type, qboolean isDynamic)
00377 {
00378     uiNode_t* node = UI_AllocNodeWithoutNew (name, type, isDynamic);
00379 
00380     /* allocate memories */
00381     if (node->dynamic && node->behaviour->new)
00382         node->behaviour->new(node);
00383 
00384     return node;
00385 }
00386 
00394 static uiNode_t *UI_GetNodeInTreeAtPosition (uiNode_t *node, int rx, int ry)
00395 {
00396     uiNode_t *find;
00397     int i;
00398 
00399     if (node->invis || node->behaviour->isVirtual || !UI_CheckVisibility(node))
00400         return NULL;
00401 
00402     /* relative to the node */
00403     rx -= node->pos[0];
00404     ry -= node->pos[1];
00405 
00406     /* check bounding box */
00407     if (rx < 0 || ry < 0 || rx >= node->size[0] || ry >= node->size[1])
00408         return NULL;
00409 
00411     find = NULL;
00412     if (node->firstChild) {
00413         uiNode_t *child;
00414         vec2_t clientPosition = {0, 0};
00415 
00416         if (node->behaviour->getClientPosition)
00417             node->behaviour->getClientPosition(node, clientPosition);
00418 
00419         rx -= clientPosition[0];
00420         ry -= clientPosition[1];
00421 
00422         for (child = node->firstChild; child; child = child->next) {
00423             uiNode_t *tmp;
00424             tmp = UI_GetNodeInTreeAtPosition(child, rx, ry);
00425             if (tmp)
00426                 find = tmp;
00427         }
00428 
00429         rx += clientPosition[0];
00430         ry += clientPosition[1];
00431     }
00432     if (find)
00433         return find;
00434 
00435     /* disable ghost/excluderect in debug mode 2 */
00436     if (UI_DebugMode() != 2) {
00437         /* is the node tangible */
00438         if (node->ghost)
00439             return NULL;
00440 
00441         /* check excluded box */
00442         for (i = 0; i < node->excludeRectNum; i++) {
00443             if (rx >= node->excludeRect[i].pos[0]
00444              && rx < node->excludeRect[i].pos[0] + node->excludeRect[i].size[0]
00445              && ry >= node->excludeRect[i].pos[1]
00446              && ry < node->excludeRect[i].pos[1] + node->excludeRect[i].size[1])
00447                 return NULL;
00448         }
00449     }
00450 
00451     /* we are over the node */
00452     return node;
00453 }
00454 
00458 uiNode_t *UI_GetNodeAtPosition (int x, int y)
00459 {
00460     int pos;
00461 
00462     /* find the first window under the mouse */
00463     for (pos = ui_global.windowStackPos - 1; pos >= 0; pos--) {
00464         uiNode_t *window = ui_global.windowStack[pos];
00465         uiNode_t *find;
00466 
00467         /* update the layout */
00468         UI_Validate(window);
00469 
00470         find = UI_GetNodeInTreeAtPosition(window, x, y);
00471         if (find)
00472             return find;
00473 
00474         /* we must not search anymore */
00475         if (UI_WindowIsDropDown(window))
00476             break;
00477         if (UI_WindowIsModal(window))
00478             break;
00479         if (UI_WindowIsFullScreen(window))
00480             break;
00481     }
00482 
00483     return NULL;
00484 }
00485 
00492 uiBehaviour_t* UI_GetNodeBehaviour (const char* name)
00493 {
00494     unsigned char min = 0;
00495     unsigned char max = NUMBER_OF_BEHAVIOURS;
00496 
00497     while (min != max) {
00498         const int mid = (min + max) >> 1;
00499         const char diff = strcmp(nodeBehaviourList[mid].name, name);
00500         assert(mid < max);
00501         assert(mid >= min);
00502 
00503         if (diff == 0)
00504             return &nodeBehaviourList[mid];
00505 
00506         if (diff > 0)
00507             max = mid;
00508         else
00509             min = mid + 1;
00510     }
00511 
00512     return NULL;
00513 }
00514 
00515 uiBehaviour_t* UI_GetNodeBehaviourByIndex (int index)
00516 {
00517     return &nodeBehaviourList[index];
00518 }
00519 
00520 int UI_GetNodeBehaviourCount (void)
00521 {
00522     return NUMBER_OF_BEHAVIOURS;
00523 }
00524 
00529 void UI_DeleteAllChild (uiNode_t* node)
00530 {
00531     uiNode_t *child;
00532     child = node->firstChild;
00533     while (child) {
00534         uiNode_t *next = child->next;
00535         UI_DeleteNode(child);
00536         child = next;
00537     }
00538 }
00539 
00544 void UI_DeleteNode (uiNode_t* node)
00545 {
00546     uiBehaviour_t *behaviour;
00547 
00548     if (!node->dynamic)
00549         return;
00550 
00551     UI_DeleteAllChild(node);
00552     if (node->firstChild != NULL) {
00553         Com_Printf("UI_DeleteNode: Node '%s' contain static nodes. We can't delete it.", UI_GetPath(node));
00554         return;
00555     }
00556 
00557     if (node->parent)
00558         UI_RemoveNode(node->parent, node);
00559 
00560     /* delete all allocated properties */
00561     for (behaviour = node->behaviour; behaviour; behaviour = behaviour->super) {
00562         const value_t *property = behaviour->properties;
00563         if (property == NULL)
00564             continue;
00565         while (property->string != NULL) {
00566             if ((property->type & V_UI_MASK) == V_UI_CVAR) {
00567                 void *mem = ((byte *) node + property->ofs);
00568                 if (*(void**)mem != NULL) {
00569                     UI_FreeStringProperty(*(void**)mem);
00570                     *(void**)mem = NULL;
00571                 }
00572             }
00573 
00576             property++;
00577         }
00578     }
00579 
00580     if (node->behaviour->delete)
00581         node->behaviour->delete(node);
00582 }
00583 
00594 uiNode_t* UI_CloneNode (const uiNode_t* node, uiNode_t *newWindow, qboolean recursive, const char *newName, qboolean isDynamic)
00595 {
00596     uiNode_t* newNode = UI_AllocNodeWithoutNew(NULL, node->behaviour->name, isDynamic);
00597 
00598     /* clone all data */
00599     memcpy(newNode, node, sizeof(*node) + node->behaviour->extraDataSize);
00600     newNode->dynamic = isDynamic;
00601 
00602     /* custom name */
00603     if (newName != NULL) {
00604         Q_strncpyz(newNode->name, newName, sizeof(newNode->name));
00605         if (strlen(newNode->name) != strlen(newName))
00606             Com_Printf("UI_CloneNode: Node name \"%s\" truncated. New name is \"%s\"\n", newName, newNode->name);
00607     }
00608 
00609     /* clean up node navigation */
00610     if (node->root == node && newWindow == NULL)
00611         newWindow = newNode;
00612     newNode->root = newWindow;
00613     newNode->parent = NULL;
00614     newNode->firstChild = NULL;
00615     newNode->lastChild = NULL;
00616     newNode->next = NULL;
00617     newNode->super = *(uiNode_t**) ((void*)&node);
00618 
00619     /* clone child */
00620     if (recursive) {
00621         uiNode_t* childNode;
00622         for (childNode = node->firstChild; childNode; childNode = childNode->next) {
00623             uiNode_t* newChildNode = UI_CloneNode(childNode, newWindow, recursive, NULL, isDynamic);
00624             UI_AppendNode(newNode, newChildNode);
00625         }
00626     }
00627 
00628     /* allocate memories */
00629     if (newNode->dynamic && newNode->behaviour->new)
00630         newNode->behaviour->new(newNode);
00631 
00632     newNode->behaviour->clone(node, newNode);
00633 
00634     return newNode;
00635 }
00636 
00638 static const int virtualFunctions[] = {
00639     offsetof(uiBehaviour_t, draw),
00640     offsetof(uiBehaviour_t, drawTooltip),
00641     offsetof(uiBehaviour_t, leftClick),
00642     offsetof(uiBehaviour_t, rightClick),
00643     offsetof(uiBehaviour_t, middleClick),
00644     offsetof(uiBehaviour_t, mouseWheel),
00645     offsetof(uiBehaviour_t, mouseMove),
00646     offsetof(uiBehaviour_t, mouseDown),
00647     offsetof(uiBehaviour_t, mouseUp),
00648     offsetof(uiBehaviour_t, capturedMouseMove),
00649     offsetof(uiBehaviour_t, loading),
00650     offsetof(uiBehaviour_t, loaded),
00651     offsetof(uiBehaviour_t, init),
00652     offsetof(uiBehaviour_t, close),
00653     offsetof(uiBehaviour_t, clone),
00654     offsetof(uiBehaviour_t, new),
00655     offsetof(uiBehaviour_t, delete),
00656     offsetof(uiBehaviour_t, activate),
00657     offsetof(uiBehaviour_t, doLayout),
00658     offsetof(uiBehaviour_t, dndEnter),
00659     offsetof(uiBehaviour_t, dndMove),
00660     offsetof(uiBehaviour_t, dndLeave),
00661     offsetof(uiBehaviour_t, dndDrop),
00662     offsetof(uiBehaviour_t, dndFinished),
00663     offsetof(uiBehaviour_t, focusGained),
00664     offsetof(uiBehaviour_t, focusLost),
00665     offsetof(uiBehaviour_t, extraDataSize),
00666     offsetof(uiBehaviour_t, sizeChanged),
00667     offsetof(uiBehaviour_t, propertyChanged),
00668     offsetof(uiBehaviour_t, getClientPosition),
00669     -1
00670 };
00671 
00676 static void UI_InitializeNodeBehaviour (uiBehaviour_t* behaviour)
00677 {
00678     if (behaviour->isInitialized)
00679         return;
00680 
00682     /* check and update properties data */
00683     if (behaviour->properties) {
00684         int num = 0;
00685         const value_t* current = behaviour->properties;
00686         while (current->string != NULL) {
00687             num++;
00688             current++;
00689         }
00690         behaviour->propertyCount = num;
00691     }
00692 
00693     /* everything inherits 'abstractnode' */
00694     if (behaviour->extends == NULL && strcmp(behaviour->name, "abstractnode") != 0) {
00695         behaviour->extends = "abstractnode";
00696     }
00697 
00698     if (behaviour->extends) {
00699         int i = 0;
00700         behaviour->super = UI_GetNodeBehaviour(behaviour->extends);
00701         UI_InitializeNodeBehaviour(behaviour->super);
00702 
00703         while (qtrue) {
00704             const size_t pos = virtualFunctions[i];
00705             uintptr_t superFunc;
00706             uintptr_t func;
00707             if (pos == -1)
00708                 break;
00709 
00710             /* cache super function if we don't overwrite it */
00711             superFunc = *(uintptr_t*)((byte*)behaviour->super + pos);
00712             func = *(uintptr_t*)((byte*)behaviour + pos);
00713             if (func == 0 && superFunc != 0)
00714                 *(uintptr_t*)((byte*)behaviour + pos) = superFunc;
00715 
00716             i++;
00717         }
00718     }
00719 
00720     /* property must not overwrite another property */
00721     if (behaviour->super && behaviour->properties) {
00722         const value_t* property = behaviour->properties;
00723         while (property->string != NULL) {
00724             const value_t *p = UI_GetPropertyFromBehaviour(behaviour->super, property->string);
00725 #if 0   
00726             const uiBehaviour_t *b = UI_GetNodeBehaviour(current->string);
00727 #endif
00728             if (p != NULL)
00729                 Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' overwrite another property", property->string, behaviour->name);
00730 #if 0   
00731             if (b != NULL)
00732                 Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' use the name of an existing node behaviour", property->string, behaviour->name);
00733 #endif
00734             property++;
00735         }
00736     }
00737 
00738     /* Sanity: A property must not be outside the node memory */
00739     if (behaviour->properties) {
00740         const int size = sizeof(uiNode_t) + behaviour->extraDataSize;
00741         const value_t* property = behaviour->properties;
00742         while (property->string != NULL) {
00743             if (property->type != V_UI_NODEMETHOD && property->ofs + property->size > size)
00744                 Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' is outside the node memory. The C code need a fix.", property->string, behaviour->name);
00745             property++;
00746         }
00747     }
00748 
00749     behaviour->isInitialized = qtrue;
00750 }
00751 
00752 void UI_InitNodes (void)
00753 {
00754     int i = 0;
00755     uiBehaviour_t *current = nodeBehaviourList;
00756 
00757     /* compute list of node behaviours */
00758     for (i = 0; i < NUMBER_OF_BEHAVIOURS; i++) {
00759         registerFunctions[i](current);
00760         current++;
00761     }
00762 
00763     /* check for safe data: list must be sorted by alphabet */
00764     current = nodeBehaviourList;
00765     assert(current);
00766     for (i = 0; i < NUMBER_OF_BEHAVIOURS - 1; i++) {
00767         const uiBehaviour_t *a = current;
00768         const uiBehaviour_t *b = current + 1;
00769         assert(b);
00770         if (strcmp(a->name, b->name) >= 0) {
00771 #ifdef DEBUG
00772             Com_Error(ERR_FATAL, "UI_InitNodes: '%s' is before '%s'. Please order node behaviour registrations by name", a->name, b->name);
00773 #else
00774             Com_Error(ERR_FATAL, "UI_InitNodes: Error: '%s' is before '%s'", a->name, b->name);
00775 #endif
00776         }
00777         current++;
00778     }
00779 
00780     /* finalize node behaviour initialization */
00781     current = nodeBehaviourList;
00782     for (i = 0; i < NUMBER_OF_BEHAVIOURS; i++) {
00783         UI_InitializeNodeBehaviour(current);
00784         current++;
00785     }
00786 }

Generated by  doxygen 1.6.2