Bug Summary

File:client/ui/ui_nodes.cpp
Location:line 268, column 4
Description:Dereference of null pointer (loaded from variable 'resultProperty')

Annotated Source Code

1/**
2 * @file
3 */
4
5/*
6Copyright (C) 2002-2011 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "ui_main.h"
26#include "ui_internal.h"
27#include "ui_node.h"
28#include "ui_nodes.h"
29#include "ui_parse.h"
30#include "ui_input.h"
31
32#include "node/ui_node_abstractnode.h"
33#include "node/ui_node_abstractscrollbar.h"
34#include "node/ui_node_abstractoption.h"
35#include "node/ui_node_abstractvalue.h"
36#include "node/ui_node_bar.h"
37#include "node/ui_node_base.h"
38#include "node/ui_node_baseinventory.h"
39#include "node/ui_node_battlescape.h"
40#include "node/ui_node_button.h"
41#include "node/ui_node_checkbox.h"
42#include "node/ui_node_controls.h"
43#include "node/ui_node_container.h"
44#include "node/ui_node_data.h"
45#include "node/ui_node_editor.h"
46#include "node/ui_node_ekg.h"
47#include "node/ui_node_geoscape.h"
48#include "node/ui_node_image.h"
49#include "node/ui_node_item.h"
50#include "node/ui_node_linechart.h"
51#include "node/ui_node_material_editor.h"
52#include "node/ui_node_messagelist.h"
53#include "node/ui_node_model.h"
54#include "node/ui_node_option.h"
55#include "node/ui_node_optionlist.h"
56#include "node/ui_node_optiontree.h"
57#include "node/ui_node_panel.h"
58#include "node/ui_node_radar.h"
59#include "node/ui_node_radiobutton.h"
60#include "node/ui_node_rows.h"
61#include "node/ui_node_selectbox.h"
62#include "node/ui_node_sequence.h"
63#include "node/ui_node_string.h"
64#include "node/ui_node_special.h"
65#include "node/ui_node_spinner.h"
66#include "node/ui_node_tab.h"
67#include "node/ui_node_tbar.h"
68#include "node/ui_node_text.h"
69#include "node/ui_node_text2.h"
70#include "node/ui_node_textlist.h"
71#include "node/ui_node_textentry.h"
72#include "node/ui_node_texture.h"
73#include "node/ui_node_timer.h"
74#include "node/ui_node_keybinding.h"
75#include "node/ui_node_todo.h"
76#include "node/ui_node_video.h"
77#include "node/ui_node_vscrollbar.h"
78#include "node/ui_node_zone.h"
79
80typedef void (*registerFunction_t)(uiBehaviour_t *node);
81
82/**
83 * @brief List of functions to register nodes
84 * @note Functions must be sorted by node name
85 */
86static const registerFunction_t registerFunctions[] = {
87 UI_RegisterNullNode,
88 UI_RegisterAbstractBaseNode,
89 UI_RegisterAbstractNode,
90 UI_RegisterAbstractOptionNode,
91 UI_RegisterAbstractScrollableNode,
92 UI_RegisterAbstractScrollbarNode,
93 UI_RegisterAbstractValueNode,
94 UI_RegisterBarNode,
95 UI_RegisterBaseInventoryNode,
96 UI_RegisterBaseLayoutNode,
97 UI_RegisterBaseMapNode,
98 UI_RegisterBattlescapeNode,
99 UI_RegisterButtonNode,
100 UI_RegisterCheckBoxNode,
101 UI_RegisterConFuncNode,
102 UI_RegisterContainerNode,
103 UI_RegisterControlsNode,
104 UI_RegisterCvarFuncNode,
105 UI_RegisterDataNode,
106 UI_RegisterEditorNode,
107 UI_RegisterEKGNode,
108 UI_RegisterFuncNode,
109 UI_RegisterGeoscapeNode,
110 UI_RegisterImageNode,
111 UI_RegisterItemNode,
112 UI_RegisterKeyBindingNode,
113 UI_RegisterLineChartNode,
114 UI_RegisterMaterialEditorNode,
115 UI_RegisterMessageListNode,
116 UI_RegisterModelNode,
117 UI_RegisterOptionNode,
118 UI_RegisterOptionListNode,
119 UI_RegisterOptionTreeNode,
120 UI_RegisterPanelNode,
121 UI_RegisterRadarNode,
122 UI_RegisterRadioButtonNode,
123 UI_RegisterRowsNode,
124 UI_RegisterSelectBoxNode,
125 UI_RegisterSequenceNode,
126 UI_RegisterSpinnerNode,
127 UI_RegisterStringNode,
128 UI_RegisterTabNode,
129 UI_RegisterTBarNode,
130 UI_RegisterTextNode,
131 UI_RegisterText2Node,
132 UI_RegisterTextEntryNode,
133 UI_RegisterTextListNode,
134 UI_RegisterTextureNode,
135 UI_RegisterTimerNode,
136 UI_RegisterTodoNode,
137 UI_RegisterVideoNode,
138 UI_RegisterVScrollbarNode,
139 UI_RegisterWindowNode,
140 UI_RegisterZoneNode
141};
142#define NUMBER_OF_BEHAVIOURS(sizeof(registerFunctions) / sizeof(*(registerFunctions))) lengthof(registerFunctions)(sizeof(registerFunctions) / sizeof(*(registerFunctions)))
143
144/**
145 * @brief List of all node behaviours, indexes by nodetype num.
146 */
147static uiBehaviour_t nodeBehaviourList[NUMBER_OF_BEHAVIOURS(sizeof(registerFunctions) / sizeof(*(registerFunctions)))];
148
149/**
150 * @brief Check the if conditions for a given node
151 * @sa V_UI_IF
152 * @returns false if the node is not drawn due to not meet if conditions
153 */
154bool UI_CheckVisibility (uiNode_t *node)
155{
156 uiCallContext_t context;
157 if (!node->visibilityCondition)
158 return true;
159 context.source = node;
160 context.useCmdParam = false;
161 return UI_GetBooleanFromExpression(node->visibilityCondition, &context);
162}
163
164/**
165 * @brief Return a path from a window to a node
166 * @return A path "windowname.nodename.nodename.givennodename"
167 * @note Use a static buffer for the result
168 */
169const char* UI_GetPath (const uiNode_t* node)
170{
171 static char result[512];
172 const uiNode_t* nodes[8];
173 int i = 0;
174
175 while (node) {
176 assert(i < 8)(__builtin_expect(!(i < 8), 0) ? __assert_rtn(__func__, "src/client/ui/ui_nodes.cpp"
, 176, "i < 8") : (void)0)
;
177 nodes[i] = node;
178 node = node->parent;
179 i++;
180 }
181
182 /** @todo we can use something faster than cat */
183 result[0] = '\0';
184 while (i) {
185 i--;
186 Q_strcat(result, nodes[i]->name, sizeof(result));
187 if (i > 0)
188 Q_strcat(result, ".", sizeof(result));
189 }
190
191 return result;
192}
193
194/**
195 * @brief Read a path and return every we can use (node and property)
196 * @details The path token must be a window name, and then node child.
197 * Reserved token 'root' and 'parent' can be used to navigate.
198 * If relativeNode is set, the path can start with reserved token
199 * 'this', 'root' and 'parent' (relative to this node).
200 * The function can return a node property by using a '\@',
201 * the path 'foo\@pos' will return the window foo and the property 'pos'
202 * from the 'window' behaviour.
203 * @param[in] path Path to read. Contain a node location with dot seprator and a facultative property
204 * @param[in] relativeNode relative node where the path start. It allow to use facultative command to start the path (this, parent, root).
205 * @param[out] resultNode Node found. Else NULL.
206 * @param[out] resultProperty Property found. Else NULL.
207 * TODO Speed up, evilly used function, use strncmp instead of using buffer copy (name[MAX_VAR])
208 */
209void UI_ReadNodePath (const char* path, const uiNode_t *relativeNode, uiNode_t **resultNode, const value_t **resultProperty)
210{
211 char name[MAX_VAR64];
212 uiNode_t* node = NULL__null;
213 const char* nextName;
214 char nextCommand = '^';
215
216 *resultNode = NULL__null;
217 if (resultProperty)
1
Taking false branch
218 *resultProperty = NULL__null;
219
220 nextName = path;
221 while (nextName && nextName[0] != '\0') {
2
Loop condition is true. Entering loop body
10
Loop condition is true. Entering loop body
222 const char* begin = nextName;
223 char command = nextCommand;
224 nextName = strpbrk(begin, ".@#");
225 if (!nextName) {
3
Taking false branch
11
Taking true branch
226 Q_strncpyz(name, begin, sizeof(name))Q_strncpyzDebug( name, begin, sizeof(name), "src/client/ui/ui_nodes.cpp"
, 226 )
;
227 nextCommand = '\0';
228 } else {
229 assert(nextName - begin + 1 <= sizeof(name))(__builtin_expect(!(nextName - begin + 1 <= sizeof(name)),
0) ? __assert_rtn(__func__, "src/client/ui/ui_nodes.cpp", 229
, "nextName - begin + 1 <= sizeof(name)") : (void)0)
;
230 Q_strncpyz(name, begin, nextName - begin + 1)Q_strncpyzDebug( name, begin, nextName - begin + 1, "src/client/ui/ui_nodes.cpp"
, 230 )
;
231 nextCommand = *nextName;
232 nextName++;
233 }
234
235 switch (command) {
4
Control jumps to 'case 94:' at line 236
12
Control jumps to 'case 64:' at line 266
236 case '^': /* first string */
237 if (Q_streq(name, "this")(strcmp(name, "this") == 0)) {
5
Taking false branch
238 if (relativeNode == NULL__null)
239 return;
240 /** @todo find a way to fix the bad cast. only here to remove "discards qualifiers" warning */
241 node = *(uiNode_t**) ((void*)&relativeNode);
242 } else if (Q_streq(name, "parent")(strcmp(name, "parent") == 0)) {
6
Taking false branch
243 if (relativeNode == NULL__null)
244 return;
245 node = relativeNode->parent;
246 } else if (Q_streq(name, "root")(strcmp(name, "root") == 0)) {
7
Taking false branch
247 if (relativeNode == NULL__null)
248 return;
249 node = relativeNode->root;
250 } else
251 node = UI_GetWindow(name);
252 break;
8
Execution continues on line 273
253 case '.': /* child node */
254 if (Q_streq(name, "parent")(strcmp(name, "parent") == 0))
255 node = node->parent;
256 else if (Q_streq(name, "root")(strcmp(name, "root") == 0))
257 node = node->root;
258 else
259 node = UI_GetNode(node, name);
260 break;
261 case '#': /* window index */
262 /** @todo FIXME use a warning instead of an assert */
263 assert(UI_Node_IsWindow(node))(__builtin_expect(!(UI_Node_IsWindow(node)), 0) ? __assert_rtn
(__func__, "src/client/ui/ui_nodes.cpp", 263, "UI_Node_IsWindow(node)"
) : (void)0)
;
264 node = UI_WindowNodeGetIndexedChild(node, name);
265 break;
266 case '@': /* property */
267 assert(nextCommand == '\0')(__builtin_expect(!(nextCommand == '\0'), 0) ? __assert_rtn(__func__
, "src/client/ui/ui_nodes.cpp", 267, "nextCommand == '\\0'") :
(void)0)
;
268 *resultProperty = UI_GetPropertyFromBehaviour(node->behaviour, name);
13
Dereference of null pointer (loaded from variable 'resultProperty')
269 *resultNode = node;
270 return;
271 }
272
273 if (!node)
9
Taking false branch
274 return;
275 }
276
277 *resultNode = node;
278 return;
279}
280
281/**
282 * @brief Return a node by a path name (names with dot separation)
283 * It is a simplification facade over UI_ReadNodePath
284 * @return The requested node, else NULL if not found
285 * @code
286 * // get keylist node from options_keys node from options window
287 * node = UI_GetNodeByPath("options.options_keys.keylist");
288 * @sa UI_ReadNodePath
289 * @endcode
290 */
291uiNode_t* UI_GetNodeByPath (const char* path)
292{
293 uiNode_t* node = NULL__null;
294 const value_t *property;
295 UI_ReadNodePath(path, NULL__null, &node, &property);
296 /** @todo FIXME warning if it return a property */
297 return node;
298}
299
300/**
301 * @brief Allocate a node into the UI memory (do not call behaviour->new)
302 * @note It's not a dynamic memory allocation. Please only use it at the loading time
303 * @todo Assert out when we are not in parsing/loading stage
304 * @param[in] name Name of the new node, else NULL if we don't want to edit it.
305 * @param[in] type Name of the node behavior
306 * @param[in] isDynamic Allocate a node in static or dynamic memory
307 */
308static uiNode_t* UI_AllocNodeWithoutNew (const char* name, const char* type, bool isDynamic)
309{
310 uiNode_t* node;
311 uiBehaviour_t *behaviour;
312 int nodeSize;
313
314 behaviour = UI_GetNodeBehaviour(type);
315 if (behaviour == NULL__null)
316 Com_Error(ERR_FATAL0, "UI_AllocNodeWithoutNew: Node behaviour '%s' doesn't exist", type);
317
318 nodeSize = sizeof(*node) + behaviour->extraDataSize;
319
320 if (!isDynamic) {
321 void *memory = UI_AllocHunkMemory(nodeSize, STRUCT_MEMORY_ALIGN8, true);
322 if (memory == NULL__null)
323 Com_Error(ERR_FATAL0, "UI_AllocNodeWithoutNew: No more memory to allocate a new node - increase the cvar ui_hunksize");
324 node = static_cast<uiNode_t*>(memory);
325 ui_global.numNodes++;
326 } else {
327 node = static_cast<uiNode_t*>(Mem_PoolAlloc(nodeSize, ui_dynPool, 0)_Mem_Alloc((nodeSize),true,(ui_dynPool),(0),"src/client/ui/ui_nodes.cpp"
,327)
);
328 node->dynamic = true;
329 }
330
331 node->behaviour = behaviour;
332#ifdef DEBUG1
333 UI_Node_DebugCountWidget(node, 1);
334#endif
335 if (UI_Node_IsAbstract(node))
336 Com_Error(ERR_FATAL0, "UI_AllocNodeWithoutNew: Node behavior '%s' is abstract. We can't instantiate it.", type);
337
338 if (name != NULL__null) {
339 Q_strncpyz(node->name, name, sizeof(node->name))Q_strncpyzDebug( node->name, name, sizeof(node->name), "src/client/ui/ui_nodes.cpp"
, 339 )
;
340 if (strlen(node->name) != strlen(name))
341 Com_Printf("UI_AllocNodeWithoutNew: Node name \"%s\" truncated. New name is \"%s\"\n", name, node->name);
342 }
343
344 /* initialize default properties */
345 UI_Node_Loading(node);
346
347 return node;
348}
349
350/**
351 * @brief Allocate a node into the UI memory
352 * @note It's not a dynamic memory allocation. Please only use it at the loading time
353 * @todo Assert out when we are not in parsing/loading stage
354 * @param[in] name Name of the new node, else NULL if we don't want to edit it.
355 * @param[in] type Name of the node behavior
356 * @param[in] isDynamic Allocate a node in static or dynamic memory
357 */
358uiNode_t* UI_AllocNode (const char* name, const char* type, bool isDynamic)
359{
360 uiNode_t* node = UI_AllocNodeWithoutNew(name, type, isDynamic);
361
362 /* allocate memory */
363 if (node->dynamic)
364 UI_Node_NewNode(node);
365
366 return node;
367}
368
369/**
370 * @brief Return the first visible node at a position
371 * @param[in] node Node where we must search
372 * @param[in] rx Relative x position to the parent of the node
373 * @param[in] ry Relative y position to the parent of the node
374 * @return The first visible node at position, else NULL
375 */
376static uiNode_t *UI_GetNodeInTreeAtPosition (uiNode_t *node, int rx, int ry)
377{
378 uiNode_t *find;
379
380 if (node->invis || UI_Node_IsVirtual(node) || !UI_CheckVisibility(node))
381 return NULL__null;
382
383 /* relative to the node */
384 rx -= node->box.pos[0];
385 ry -= node->box.pos[1];
386
387 /* check bounding box */
388 if (rx < 0 || ry < 0 || rx >= node->box.size[0] || ry >= node->box.size[1])
389 return NULL__null;
390
391 /** @todo we should improve the loop (last-to-first) */
392 find = NULL__null;
393 if (node->firstChild) {
394 uiNode_t *child;
395 vec2_t clientPosition = {0, 0};
396
397 if (UI_Node_IsScrollableContainer(node))
398 UI_Node_GetClientPosition(node, clientPosition);
399
400 rx -= clientPosition[0];
401 ry -= clientPosition[1];
402
403 for (child = node->firstChild; child; child = child->next) {
404 uiNode_t *tmp;
405 tmp = UI_GetNodeInTreeAtPosition(child, rx, ry);
406 if (tmp)
407 find = tmp;
408 }
409
410 rx += clientPosition[0];
411 ry += clientPosition[1];
412 }
413 if (find)
414 return find;
415
416 /* disable ghost/excluderect in debug mode 2 */
417 if (UI_DebugMode() != 2) {
418 uiExcludeRect_t *excludeRect;
419 /* is the node tangible */
420 if (node->ghost)
421 return NULL__null;
422
423 /* check excluded box */
424 for (excludeRect = node->firstExcludeRect; excludeRect != NULL__null; excludeRect = excludeRect->next) {
425 if (rx >= excludeRect->pos[0]
426 && rx < excludeRect->pos[0] + excludeRect->size[0]
427 && ry >= excludeRect->pos[1]
428 && ry < excludeRect->pos[1] + excludeRect->size[1])
429 return NULL__null;
430 }
431 }
432
433 /* we are over the node */
434 return node;
435}
436
437/**
438 * @brief Return the first visible node at a position
439 */
440uiNode_t *UI_GetNodeAtPosition (int x, int y)
441{
442 int pos;
443
444 /* find the first window under the mouse */
445 for (pos = ui_global.windowStackPos - 1; pos >= 0; pos--) {
446 uiNode_t *window = ui_global.windowStack[pos];
447 uiNode_t *find;
448
449 /* update the layout */
450 UI_Validate(window);
451
452 find = UI_GetNodeInTreeAtPosition(window, x, y);
453 if (find)
454 return find;
455
456 /* we must not search anymore */
457 if (UI_WindowIsDropDown(window))
458 break;
459 if (UI_WindowIsModal(window))
460 break;
461 if (UI_WindowIsFullScreen(window))
462 break;
463 }
464
465 return NULL__null;
466}
467
468/**
469 * @brief Return a node behaviour by name
470 * @note Use a dichotomic search. nodeBehaviourList must be sorted by name.
471 * @param[in] name Behaviour name requested
472 * @return The bahaviour found, else NULL
473 */
474uiBehaviour_t* UI_GetNodeBehaviour (const char* name)
475{
476 unsigned char min = 0;
477 unsigned char max = NUMBER_OF_BEHAVIOURS(sizeof(registerFunctions) / sizeof(*(registerFunctions)));
478
479 while (min != max) {
480 const int mid = (min + max) >> 1;
481 const int diff = strcmp(nodeBehaviourList[mid].name, name);
482 assert(mid < max)(__builtin_expect(!(mid < max), 0) ? __assert_rtn(__func__
, "src/client/ui/ui_nodes.cpp", 482, "mid < max") : (void)
0)
;
483 assert(mid >= min)(__builtin_expect(!(mid >= min), 0) ? __assert_rtn(__func__
, "src/client/ui/ui_nodes.cpp", 483, "mid >= min") : (void
)0)
;
484
485 if (diff == 0)
486 return &nodeBehaviourList[mid];
487
488 if (diff > 0)
489 max = mid;
490 else
491 min = mid + 1;
492 }
493
494 return NULL__null;
495}
496
497uiBehaviour_t* UI_GetNodeBehaviourByIndex (int index)
498{
499 return &nodeBehaviourList[index];
500}
501
502int UI_GetNodeBehaviourCount (void)
503{
504 return NUMBER_OF_BEHAVIOURS(sizeof(registerFunctions) / sizeof(*(registerFunctions)));
505}
506
507/**
508 * @brief Remove all child from a node (only remove dynamic memory allocation nodes)
509 * @param node The node we want to clean
510 */
511void UI_DeleteAllChild (uiNode_t* node)
512{
513 uiNode_t *child;
514 child = node->firstChild;
515 while (child) {
516 uiNode_t *next = child->next;
517 UI_DeleteNode(child);
518 child = next;
519 }
520}
521
522static void UI_BeforeDeletingNode (const uiNode_t* node)
523{
524 if (UI_GetHoveredNode() == node) {
525 UI_InvalidateMouse();
526 }
527}
528
529/**
530 * Delete the node and remove it from his parent
531 * @param node The node we want to delete
532 */
533void UI_DeleteNode (uiNode_t* node)
534{
535 uiBehaviour_t *behaviour;
536
537 if (!node->dynamic)
538 return;
539
540 UI_BeforeDeletingNode(node);
541
542 UI_DeleteAllChild(node);
543 if (node->firstChild != NULL__null) {
544 Com_Printf("UI_DeleteNode: Node '%s' contain static nodes. We can't delete it.\n", UI_GetPath(node));
545 return;
546 }
547
548 if (node->parent)
549 UI_RemoveNode(node->parent, node);
550
551 /* delete all allocated properties */
552 for (behaviour = node->behaviour; behaviour; behaviour = behaviour->super) {
553 const value_t **property = behaviour->localProperties;
554 if (property == NULL__null)
555 continue;
556 while (*property) {
557 if (((*property)->type & V_UI_MASK0x8F00) == V_UI_CVAR(0x8000 + 0x0100)) {
558 if (void*& mem = Com_GetValue<void*>(node, *property)) {
559 UI_FreeStringProperty(mem);
560 mem = 0;
561 }
562 }
563
564 /** @todo We must delete all EA_LISTENER too */
565
566 property++;
567 }
568 }
569
570 UI_Node_DeleteNode(node);
571}
572
573/**
574 * @brief Clone a node
575 * @param[in] node Node to clone
576 * @param[in] recursive True if we also must clone subnodes
577 * @param[in] newWindow Window where the nodes must be add (this function only link node into window, not window into the new node)
578 * @param[in] newName New node name, else NULL to use the source name
579 * @param[in] isDynamic Allocate a node in static or dynamic memory
580 * @todo exclude rect is not safe cloned.
581 * @todo actions are not cloned. It is be a problem if we use add/remove listener into a cloned node.
582 */
583uiNode_t* UI_CloneNode (const uiNode_t* node, uiNode_t *newWindow, bool recursive, const char *newName, bool isDynamic)
584{
585 uiNode_t* newNode = UI_AllocNodeWithoutNew(NULL__null, UI_Node_GetWidgetName(node), isDynamic);
586
587 /* clone all data */
588 memcpy(newNode, node, UI_Node_GetMemorySize(node));
589 newNode->dynamic = isDynamic;
590
591 /* custom name */
592 if (newName != NULL__null) {
593 Q_strncpyz(newNode->name, newName, sizeof(newNode->name))Q_strncpyzDebug( newNode->name, newName, sizeof(newNode->
name), "src/client/ui/ui_nodes.cpp", 593 )
;
594 if (strlen(newNode->name) != strlen(newName))
595 Com_Printf("UI_CloneNode: Node name \"%s\" truncated. New name is \"%s\"\n", newName, newNode->name);
596 }
597
598 /* clean up node navigation */
599 if (node->root == node && newWindow == NULL__null)
600 newWindow = newNode;
601 newNode->root = newWindow;
602 newNode->parent = NULL__null;
603 newNode->firstChild = NULL__null;
604 newNode->lastChild = NULL__null;
605 newNode->next = NULL__null;
606 newNode->super = node;
607
608 /* clone child */
609 if (recursive) {
610 uiNode_t* childNode;
611 for (childNode = node->firstChild; childNode; childNode = childNode->next) {
612 uiNode_t* newChildNode = UI_CloneNode(childNode, newWindow, recursive, NULL__null, isDynamic);
613 UI_AppendNode(newNode, newChildNode);
614 }
615 }
616
617 /* allocate memories */
618 if (newNode->dynamic)
619 UI_Node_NewNode(newNode);
620
621 UI_Node_Clone(node, newNode);
622
623 return newNode;
624}
625
626void UI_InitNodes (void)
627{
628 int i = 0;
629 uiBehaviour_t *current = nodeBehaviourList;
630
631 /* compute list of node behaviours */
632 for (i = 0; i < NUMBER_OF_BEHAVIOURS(sizeof(registerFunctions) / sizeof(*(registerFunctions))); i++) {
633 OBJZERO(*current)(memset(&((*current)), (0), sizeof((*current))));
634 current->registration = true;
635 registerFunctions[i](current);
636 current->registration = false;
637 current++;
638 }
639
640 /* check for safe data: list must be sorted by alphabet */
641 current = nodeBehaviourList;
642 assert(current)(__builtin_expect(!(current), 0) ? __assert_rtn(__func__, "src/client/ui/ui_nodes.cpp"
, 642, "current") : (void)0)
;
643 for (i = 0; i < NUMBER_OF_BEHAVIOURS(sizeof(registerFunctions) / sizeof(*(registerFunctions))) - 1; i++) {
644 const uiBehaviour_t *a = current;
645 const uiBehaviour_t *b = current + 1;
646 assert(b)(__builtin_expect(!(b), 0) ? __assert_rtn(__func__, "src/client/ui/ui_nodes.cpp"
, 646, "b") : (void)0)
;
647 if (strcmp(a->name, b->name) >= 0) {
648#ifdef DEBUG1
649 Com_Error(ERR_FATAL0, "UI_InitNodes: '%s' is before '%s'. Please order node behaviour registrations by name", a->name, b->name);
650#else
651 Com_Error(ERR_FATAL0, "UI_InitNodes: Error: '%s' is before '%s'", a->name, b->name);
652#endif
653 }
654 current++;
655 }
656
657 /* finalize node behaviour initialization */
658 current = nodeBehaviourList;
659 for (i = 0; i < NUMBER_OF_BEHAVIOURS(sizeof(registerFunctions) / sizeof(*(registerFunctions))); i++) {
660 UI_InitializeNodeBehaviour(current);
661 current++;
662 }
663}
664
665void uiBox_t::alignBox (uiBox_t& inner, align_t direction)
666{
667 switch (direction % 3) {
668 case 0: /* left */
669 inner.pos[0] = this->pos[0];
670 break;
671 case 1: /* middle */
672 inner.pos[0] = this->pos[0] + (this->size[0] * 0.5) - (inner.size[0] * 0.5);
673 break;
674 case 2: /* right */
675 inner.pos[0] = this->pos[0] + this->size[0] - inner.size[0];
676 break;
677 }
678 switch (direction / 3) {
679 case 0: /* top */
680 inner.pos[1] = this->pos[1];
681 break;
682 case 1: /* middle */
683 inner.pos[1] = this->pos[1] + (this->size[1] * 0.5) - (inner.size[1] * 0.5);
684 break;
685 case 2: /* bottom */
686 inner.pos[1] = this->pos[1] + this->size[1] - inner.size[1];
687 break;
688 default:
689 inner.pos[1] = this->pos[1];
690 Com_Error(ERR_FATAL0, "UI_ImageAlignBoxInBox: Align %d not supported\n", direction);
691 }
692}