UFO: Alien Invasion
Loading...
Searching...
No Matches
ui_parse.cpp
Go to the documentation of this file.
1
7
8/*
9Copyright (C) 2002-2025 UFO: Alien Invasion.
10
11This program is free software; you can redistribute it and/or
12modify it under the terms of the GNU General Public License
13as published by the Free Software Foundation; either version 2
14of the License, or (at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20See the GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License
23along with this program; if not, write to the Free Software
24Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26*/
27
28#include "../client.h"
29#include "ui_parse.h"
30#include "ui_main.h"
31#include "ui_node.h"
32#include "ui_data.h"
33#include "ui_internal.h"
34#include "ui_actions.h"
35#include "ui_sprite.h"
36#include "ui_components.h"
37#include "node/ui_node_window.h"
41
42#include "../../shared/parse.h"
43#include "../cl_language.h"
44
46static bool UI_ParseProperty(void* object, const value_t* property, const char* objectName, const char** text, const char** token);
47static uiAction_t* UI_ParseActionList(uiNode_t* node, const char** text, const char** token);
48static uiNode_t* UI_ParseNode(uiNode_t* parent, const char** text, const char** token, const char* errhead);
49
51static const value_t uiModelProperties[] = {
52 {"model", V_HUNK_STRING, offsetof(uiModel_t, model), 0},
53 {"need", V_NULL, 0, 0},
54 {"anim", V_HUNK_STRING, offsetof(uiModel_t, anim), 0},
55 {"skin", V_INT, offsetof(uiModel_t, skin), sizeof(int)},
56 {"color", V_COLOR, offsetof(uiModel_t, color), sizeof(vec4_t)},
57 {"tag", V_HUNK_STRING, offsetof(uiModel_t, tag), 0},
58 {"parent", V_HUNK_STRING, offsetof(uiModel_t, parent), 0},
59
60 {nullptr, V_NULL, 0, 0},
61};
62
66static char const* const reservedTokens[] = {
67 "this",
68 "parent",
69 "root",
70 "null",
71 "super",
72 "node",
73 "cvar",
74 "int",
75 "float",
76 "string",
77 "var",
78 "child",
79 nullptr
80};
81
82bool UI_TokenIsReserved (const char* name)
83{
84 char const* const* token = reservedTokens;
85 while (*token) {
86 if (Q_streq(*token, name))
87 return true;
88 token++;
89 }
90 return false;
91}
92
93static bool UI_TokenIsValue (const char* name, bool isQuoted)
94{
95 assert(name);
96 if (isQuoted)
97 return true;
98 /* is it a number */
99 if ((name[0] >= '0' && name[0] <= '9') || name[0] == '-' || name[0] == '.')
100 return true;
101 /* is it a var (*cvar:...) */
102 if (name[0] == '*')
103 return true;
104 if (Q_streq(name, "true"))
105 return true;
106 if (Q_streq(name, "false"))
107 return true;
108
109 /* uppercase const name */
110 if ((name[0] >= 'A' && name[0] <= 'Z') || name[0] == '_') {
111 bool onlyUpperCase = true;
112 while (*name != '\0') {
113 if ((name[0] >= 'A' && name[0] <= 'Z') || name[0] == '_' || (name[0] >= '0' && name[0] <= '9')) {
114 /* available chars */
115 } else {
116 return false;
117 }
118 name++;
119 }
120 return onlyUpperCase;
121 }
122
123 return false;
124}
125
126bool UI_TokenIsName (const char* name, bool isQuoted)
127{
128 assert(name);
129 if (isQuoted)
130 return false;
131 if ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z') || name[0] == '_') {
132 bool onlyUpperCase = true;
133 while (*name != '\0') {
134 if (name[0] >= 'a' && name[0] <= 'z') {
135 onlyUpperCase = false;
136 } else if ((name[0] >= '0' && name[0] <= '9') || (name[0] >= 'A' && name[0] <= 'Z') || name[0] == '_') {
137 /* available chars */
138 } else {
139 return false;
140 }
141 name++;
142 }
143 return !onlyUpperCase;
144 }
145 return false;
146}
147
154const value_t* UI_FindPropertyByName (const value_t* propertyList, const char* name)
155{
156 const value_t* current = propertyList;
157 while (current->string != nullptr) {
158 if (!Q_strcasecmp(name, current->string))
159 return current;
160 current++;
161 }
162 return nullptr;
163}
164
172{
173 float* result;
174 assert(count > 0);
175 result = (float*) UI_AllocHunkMemory(sizeof(float) * count, sizeof(float), false);
176 if (result == nullptr)
177 Com_Error(ERR_FATAL, "UI_AllocFloat: UI memory hunk exceeded - increase the size");
178 return result;
179}
180
188{
189 vec4_t* result;
190 assert(count > 0);
191 result = (vec4_t*) UI_AllocHunkMemory(sizeof(vec_t) * 4 * count, sizeof(vec_t), false);
192 if (result == nullptr)
193 Com_Error(ERR_FATAL, "UI_AllocColor: UI memory hunk exceeded - increase the size");
194 return result;
195}
196
204char* UI_AllocStaticString (const char* string, int size)
205{
206 char* result;
207 if (size == 0) {
208 size = strlen(string) + 1;
209 }
210 result = (char*) UI_AllocHunkMemory(size, sizeof(char), false);
211 if (result == nullptr)
212 Com_Error(ERR_FATAL, "UI_AllocString: UI memory hunk exceeded - increase the size");
213 Q_strncpyz(result, string, size);
214 return result;
215}
216
222{
223 if (ui_global.numActions >= UI_MAX_ACTIONS)
224 Com_Error(ERR_FATAL, "UI_AllocAction: Too many UI actions");
225 return &ui_global.actions[ui_global.numActions++];
226}
227
238bool UI_InitRawActionValue (uiAction_t* action, uiNode_t* node, const value_t* property, const char* string)
239{
240 if (property == nullptr) {
241 action->type = EA_VALUE_STRING;
242 action->d.terminal.d1.data = UI_AllocStaticString(string, 0);
243 action->d.terminal.d2.integer = 0;
244 return true;
245 }
246
247 if (property->type == V_UI_SPRITEREF) {
248 uiSprite_t* sprite = UI_GetSpriteByName(string);
249 if (sprite == nullptr) {
250 Com_Printf("UI_ParseSetAction: sprite '%s' not found (%s)\n", string, UI_GetPath(node));
251 return false;
252 }
253 action->type = EA_VALUE_RAW;
254 action->d.terminal.d1.data = sprite;
255 action->d.terminal.d2.integer = property->type;
256 return true;
257 } else {
258 const int baseType = property->type & V_UI_MASK;
259 if (baseType != 0 && baseType != V_UI_CVAR) {
260 Com_Printf("UI_ParseRawValue: setter for property '%s' (type %d, 0x%X) is not supported (%s)\n", property->string, property->type, property->type, UI_GetPath(node));
261 return false;
262 }
263 ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t) (property->type & V_BASETYPEMASK));
264 action->type = EA_VALUE_RAW;
265 action->d.terminal.d1.data = ui_global.curadata;
266 action->d.terminal.d2.integer = property->type;
268 ui_global.curadata += Com_EParseValue(ui_global.curadata, string, (valueTypes_t) (property->type & V_BASETYPEMASK), 0, property->size);
269 return true;
270 }
271}
272
276static bool UI_ParseSetAction (uiNode_t* node, uiAction_t* action, const char** text, const char** token, const char* errhead)
277{
278 const value_t* property;
279 int type;
280 uiAction_t* localAction;
281
282 assert((*token)[0] == '*');
283
285 action->d.nonTerminal.left = UI_ParseExpression(text);
286
287 type = action->d.nonTerminal.left->type;
290 Com_Printf("UI_ParseSetAction: Cvar or Node property expected. Type '%i' found\n", type);
291 return false;
292 }
293
294 /* must use "equal" char between name and value */
295 *token = Com_EParse(text, errhead, nullptr);
296 if (!*text)
297 return false;
298 if (!Q_streq(*token, "=")) {
299 Com_Printf("UI_ParseSetAction: Assign sign '=' expected between variable and value. '%s' found in node %s.\n", *token, UI_GetPath(node));
300 return false;
301 }
302
303 /* get the value */
305 action->d.nonTerminal.right = UI_ParseExpression(text);
306 return true;
307 }
308
309 property = (const value_t*) action->d.nonTerminal.left->d.terminal.d2.data;
310
311 *token = Com_EParse(text, errhead, nullptr);
312 if (!*text)
313 return false;
314
315 if (Q_streq(*token, "{")) {
316 uiAction_t* actionList;
317
318 if (property != nullptr && property->type != V_UI_ACTION) {
319 Com_Printf("UI_ParseSetAction: Property %s@%s do not expect code block.\n", UI_GetPath(node), property->string);
320 return false;
321 }
322
323 actionList = UI_ParseActionList(node, text, token);
324 if (actionList == nullptr)
325 return false;
326
327 localAction = UI_AllocStaticAction();
328 localAction->type = EA_VALUE_RAW;
329 localAction->d.terminal.d1.data = actionList;
330 localAction->d.terminal.d2.integer = V_UI_ACTION;
331 action->d.nonTerminal.right = localAction;
332
333 return true;
334 }
335
336 if (Q_streq(*token, "(")) {
338 action->d.nonTerminal.right = UI_ParseExpression(text);
339 return true;
340 }
341
342 /* @todo everything should come from UI_ParseExpression */
343
344 if (UI_IsInjectedString(*token)) {
345 localAction = UI_AllocStaticAction();
346 localAction->type = EA_VALUE_STRING_WITHINJECTION;
347 localAction->d.terminal.d1.data = UI_AllocStaticString(*token, 0);
348 action->d.nonTerminal.right = localAction;
349 return true;
350 }
351
352 localAction = UI_AllocStaticAction();
353 UI_InitRawActionValue(localAction, node, property, *token);
354 action->d.nonTerminal.right = localAction;
355 return true;
356}
357
361static bool UI_ParseCallAction (uiNode_t* node, uiAction_t* action, const char** text, const char** token, const char* errhead)
362{
363 uiAction_t* expression;
364 uiAction_t* lastParam = nullptr;
365 int paramID = 0;
366 expression = UI_ParseExpression(text);
367 if (expression == nullptr)
368 return false;
369
370 if (expression->type != EA_VALUE_PATHNODE_WITHINJECTION && expression->type != EA_VALUE_PATHNODE && expression->type != EA_VALUE_PATHPROPERTY && expression->type != EA_VALUE_PATHPROPERTY_WITHINJECTION) {
371 Com_Printf("UI_ParseCallAction: \"call\" keyword only support pathnode and pathproperty (node: %s)\n", UI_GetPath(node));
372 return false;
373 }
374
375 action->d.nonTerminal.left = expression;
376
377 /* check parameters */
378 *token = Com_EParse(text, errhead, nullptr);
379 if ((*token)[0] == '\0')
380 return false;
381
382 /* there is no parameters */
383 if (!Q_streq(*token, "(")) {
385 return true;
386 }
387
388 /* read parameters */
389 do {
390 uiAction_t* param;
391 paramID++;
392
393 /* parameter */
394 param = UI_ParseExpression(text);
395 if (param == nullptr) {
396 Com_Printf("UI_ParseCallAction: problem with the %i parameter\n", paramID);
397 return false;
398 }
399 if (lastParam == nullptr)
400 action->d.nonTerminal.right = param;
401 else
402 lastParam->next = param;
403 lastParam = param;
404
405 /* separator */
406 *token = Com_EParse(text, errhead, nullptr);
407 if (!*token)
408 return false;
409 if (!Q_streq(*token, ",")) {
410 if (Q_streq(*token, ")"))
411 break;
413 Com_Printf("UI_ParseCallAction: Invalidate end of 'call' after param %i\n", paramID);
414 return false;
415 }
416 } while(true);
417
418 return true;
419}
420
427static uiAction_t* UI_ParseActionList (uiNode_t* node, const char** text, const char** token)
428{
429 const char* errhead = "UI_ParseActionList: unexpected end of file (in event)";
430 uiAction_t* firstAction;
431 uiAction_t* lastAction;
432 uiAction_t* action;
433
434 lastAction = nullptr;
435 firstAction = nullptr;
436
437 /* prevent bad position */
438 if ((*token)[0] != '{') {
439 Com_Printf("UI_ParseActionList: token \"{\" expected, but \"%s\" found (in event) (node: %s)\n", *token, UI_GetPath(node));
440 return nullptr;
441 }
442
443 while (true) {
444 bool result;
445 int type = EA_NULL;
446
447 /* get new token */
448 *token = Com_EParse(text, errhead, nullptr);
449 if (!*token)
450 return nullptr;
451
452 if ((*token)[0] == '}')
453 break;
454
456 /* setter form */
457 if (type == EA_NULL && (*token)[0] == '*')
458 type = EA_ASSIGN;
459
460 /* unknown, we break the parsing */
461 if (type == EA_NULL) {
462 Com_Printf("UI_ParseActionList: unknown token \"%s\" ignored (in event) (node: %s)\n", *token, UI_GetPath(node));
463 return nullptr;
464 }
465
466 /* add the action */
467 action = UI_AllocStaticAction();
469 if (lastAction)
470 lastAction->next = action;
471 if (!firstAction)
472 firstAction = action;
473 action->type = type;
474
475 /* decode action */
476 switch (action->type) {
477 case EA_CMD:
478 /* get parameter values */
479 *token = Com_EParse(text, errhead, nullptr);
480 if (!*text)
481 return nullptr;
482
483 /* get the value */
484 action->d.terminal.d1.constString = UI_AllocStaticString(*token, 0);
485 break;
486
487 case EA_ASSIGN:
488 result = UI_ParseSetAction(node, action, text, token, errhead);
489 if (!result)
490 return nullptr;
491 break;
492
493 case EA_CALL:
494 result = UI_ParseCallAction(node, action, text, token, errhead);
495 if (!result)
496 return nullptr;
497 break;
498
499 case EA_DELETE:
500 {
501 uiAction_t* expression;
502 expression = UI_ParseExpression(text);
503 if (expression == nullptr)
504 return nullptr;
505
506 if (expression->type != EA_VALUE_CVARNAME) {
507 Com_Printf("UI_ParseActionList: \"delete\" keyword only support cvarname (node: %s)\n", UI_GetPath(node));
508 return nullptr;
509 }
510
511 action->d.nonTerminal.left = expression;
512 break;
513 }
514 case EA_ELIF:
515 /* check previous action */
516 if (!lastAction || (lastAction->type != EA_IF && lastAction->type != EA_ELIF)) {
517 Com_Printf("UI_ParseActionList: 'elif' must be set after an 'if' or an 'elif' (node: %s)\n", UI_GetPath(node));
518 return nullptr;
519 }
520 /* then it execute EA_IF, fall through */
521 case EA_WHILE:
522 case EA_IF:
523 {
524 uiAction_t* expression;
525
526 /* get the condition */
527 expression = UI_ParseExpression(text);
528 if (expression == nullptr)
529 return nullptr;
530 action->d.nonTerminal.left = expression;
531
532 /* get the action block */
533 *token = Com_EParse(text, errhead, nullptr);
534 if (!*text)
535 return nullptr;
536 action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
537 if (action->d.nonTerminal.right == nullptr) {
538 switch (action->type) {
539 case EA_IF:
540 Com_Printf("UI_ParseActionList: block expected after \"if\" (node: %s)\n", UI_GetPath(node));
541 break;
542 case EA_ELIF:
543 Com_Printf("UI_ParseActionList: block expected after \"elif\" (node: %s)\n", UI_GetPath(node));
544 break;
545 case EA_WHILE:
546 Com_Printf("UI_ParseActionList: block expected after \"while\" (node: %s)\n", UI_GetPath(node));
547 break;
548 default:
549 Com_Printf("UI_ParseActionList: cannot determine statement type (node: %s)\n", UI_GetPath(node));
550 }
551 return nullptr;
552 }
553 break;
554 }
555
556 case EA_FORCHILDIN:
557 {
558 uiAction_t* expression;
559
560 /* get the node */
561 expression = UI_ParseExpression(text);
562 if (expression == nullptr) {
563 return nullptr;
564 }
565 action->d.nonTerminal.left = expression;
566
567 /* check the type */
568 type = action->d.nonTerminal.left->type;
570 Com_Printf("UI_ParseActionList: Node property expected. Type '%x' found\n", type);
571 return nullptr;
572 }
573
574 /* get the action block */
575 *token = Com_EParse(text, errhead, nullptr);
576 if (!*text)
577 return nullptr;
578 action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
579 if (action->d.nonTerminal.right == nullptr) {
580 Com_Printf("UI_ParseActionList: block expected after \"forchildin\" (node: %s)\n", UI_GetPath(node));
581 return nullptr;
582 }
583 break;
584 }
585
586 case EA_ELSE:
587 /* check previous action */
588 if (!lastAction || (lastAction->type != EA_IF && lastAction->type != EA_ELIF)) {
589 Com_Printf("UI_ParseActionList: 'else' must be set after an 'if' or an 'elif' (node: %s)\n", UI_GetPath(node));
590 return nullptr;
591 }
592
593 /* get the action block */
594 *token = Com_EParse(text, errhead, nullptr);
595 if (!*text)
596 return nullptr;
597 action->d.nonTerminal.left = nullptr;
598 action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
599 if (action->d.nonTerminal.right == nullptr) {
600 Com_Printf("UI_ParseActionList: block expected after \"else\" (node: %s)\n", UI_GetPath(node));
601 return nullptr;
602 }
603 break;
604
605 default:
606 assert(false);
607 }
608
609 /* step */
610 lastAction = action;
611 }
612
613 assert((*token)[0] == '}');
614
615 /* return non nullptr value */
616 if (firstAction == nullptr) {
617 firstAction = UI_AllocStaticAction();
618 }
619
620 return firstAction;
621}
622
623static bool UI_ParseExcludeRect (uiNode_t* node, const char** text, const char** token, const char* errhead)
624{
625 uiExcludeRect_t rect;
626 uiExcludeRect_t* newRect;
627
628 /* get parameters */
629 *token = Com_EParse(text, errhead, node->name);
630 if (!*text)
631 return false;
632 if ((*token)[0] != '{') {
633 Com_Printf("UI_ParseExcludeRect: node with bad excluderect ignored (node \"%s\")\n", UI_GetPath(node));
634 return true;
635 }
636
637 do {
638 *token = Com_EParse(text, errhead, node->name);
639 if (!*text)
640 return false;
642 if (Q_streq(*token, "pos")) {
643 *token = Com_EParse(text, errhead, node->name);
644 if (!*text)
645 return false;
646 Com_EParseValue(&rect, *token, V_POS, offsetof(uiExcludeRect_t, pos), sizeof(vec2_t));
647 } else if (Q_streq(*token, "size")) {
648 *token = Com_EParse(text, errhead, node->name);
649 if (!*text)
650 return false;
651 Com_EParseValue(&rect, *token, V_POS, offsetof(uiExcludeRect_t, size), sizeof(vec2_t));
652 }
653 } while ((*token)[0] != '}');
654
655 newRect = (uiExcludeRect_t*) UI_AllocHunkMemory(sizeof(*newRect), STRUCT_MEMORY_ALIGN, false);
656 if (newRect == nullptr) {
657 Com_Printf("UI_ParseExcludeRect: ui hunk memory exceeded.");
658 return false;
659 }
660
661 /* move data to final memory and link to node */
662 *newRect = rect;
663 newRect->next = node->firstExcludeRect;
664 node->firstExcludeRect = newRect;
665 return true;
666}
667
668static bool UI_ParseEventProperty (uiNode_t* node, const value_t* event, const char** text, const char** token, const char* errhead)
669{
670 /* add new actions to end of list */
671 uiAction_t** action = &Com_GetValue<uiAction_t*>(node, event);
672 for (; *action; action = &(*action)->next) {}
673
674 /* get the action body */
675 *token = Com_EParse(text, errhead, node->name);
676 if (!*text)
677 return false;
678
679 if ((*token)[0] != '{') {
680 Com_Printf("UI_ParseEventProperty: Event '%s' without body (%s)\n", event->string, UI_GetPath(node));
681 return false;
682 }
683
684 *action = UI_ParseActionList(node, text, token);
685 if (*action == nullptr)
686 return false;
687
688 /* block terminal already read */
689 assert((*token)[0] == '}');
690
691 return true;
692}
693
698static bool UI_ParseProperty (void* object, const value_t* property, const char* objectName, const char** text, const char** token)
699{
700 const char* errhead = "UI_ParseProperty: unexpected end of file (object";
701 static const char* notWellFormedValue = "UI_ParseProperty: \"%s\" is not a well formed node name (it must be quoted, uppercase const, a number, or prefixed with '*')\n";
702 size_t bytes;
703 int result;
704 const int specialType = property->type & V_UI_MASK;
705
706 if (property->type == V_NULL) {
707 return false;
708 }
709
710 switch (specialType) {
711 case V_NOT_UI: /* common type */
712
713 *token = Com_EParse(text, errhead, objectName);
714 if (!*text)
715 return false;
716 if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
717 Com_Printf(notWellFormedValue, *token);
718 return false;
719 }
720
721 if (property->type == V_TRANSLATION_STRING) {
722 /* selectbox values are static arrays */
723 char* const target = Com_GetValue<char[]>(object, property);
724 const char* translatableToken = *token;
725 assert(property->size);
726 if (translatableToken[0] == '_')
727 translatableToken++;
728 Q_strncpyz(target, translatableToken, property->size);
729 } else {
730 result = Com_ParseValue(object, *token, property->type, property->ofs, property->size, &bytes);
731 if (result != RESULT_OK) {
732 Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
733 return false;
734 }
735 }
736 break;
737
738 case V_UI_REF:
739 *token = Com_EParse(text, errhead, objectName);
740 if (!*text)
741 return false;
742 if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
743 Com_Printf(notWellFormedValue, *token);
744 return false;
745 }
746
747 /* a reference to data is handled like this */
748 ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t) (property->type & V_BASETYPEMASK));
749 Com_GetValue<byte*>(object, property) = ui_global.curadata;
750
752 assert((*token)[0] != '*');
753
754 /* sanity check */
755 if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) {
756 Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
757 return false;
758 }
759
760 result = Com_ParseValue(ui_global.curadata, *token, (valueTypes_t) (property->type & V_BASETYPEMASK), 0, property->size, &bytes);
761 if (result != RESULT_OK) {
762 Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
763 return false;
764 }
765 ui_global.curadata += bytes;
766
767 break;
768
769 case V_UI_CVAR: /* common type */
770 *token = Com_EParse(text, errhead, objectName);
771 if (!*text)
772 return false;
773 if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
774 Com_Printf(notWellFormedValue, *token);
775 return false;
776 }
777
778 /* references are parsed as string */
779 if ((*token)[0] == '*') {
780 /* a reference to data */
781 ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, V_STRING);
782 Com_GetValue<byte*>(object, property) = ui_global.curadata;
783
784 /* sanity check */
785 if (strlen(*token) > MAX_VAR - 1) {
786 Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
787 return false;
788 }
789
790 result = Com_ParseValue(ui_global.curadata, *token, V_STRING, 0, 0, &bytes);
791 if (result != RESULT_OK) {
792 Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
793 return false;
794 }
795 ui_global.curadata += bytes;
796 } else {
797 /* a reference to data */
798 ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t)(property->type & V_BASETYPEMASK));
799 Com_GetValue<byte*>(object, property) = ui_global.curadata;
800
801 /* sanity check */
802 if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) {
803 Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
804 return false;
805 }
806
807 result = Com_ParseValue(ui_global.curadata, *token, (valueTypes_t)(property->type & V_BASETYPEMASK), 0, property->size, &bytes);
808 if (result != RESULT_OK) {
809 Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
810 return false;
811 }
812 ui_global.curadata += bytes;
813 }
814 break;
815
816 case V_UI:
817
818 switch ((int)property->type) {
819 case V_UI_ACTION:
820 result = UI_ParseEventProperty(static_cast<uiNode_t*>(object), property, text, token, errhead);
821 if (!result)
822 return false;
823 break;
824
825 case V_UI_EXCLUDERECT:
826 result = UI_ParseExcludeRect(static_cast<uiNode_t*>(object), text, token, errhead);
827 if (!result)
828 return false;
829 break;
830
831 case V_UI_SPRITEREF:
832 {
833 *token = Com_EParse(text, errhead, objectName);
834 if (!*text)
835 return false;
836
837 uiSprite_t const*& sprite = Com_GetValue<uiSprite_t const*>(object, property);
838 sprite = UI_GetSpriteByName(*token);
839 if (!sprite) {
840 Com_Printf("UI_ParseProperty: sprite '%s' not found (object %s)\n", *token, objectName);
841 }
842 }
843 break;
844
845 case V_UI_IF:
846 {
847 *token = Com_EParse(text, errhead, objectName);
848 if (!*text)
849 return false;
850
851 uiAction_t*& expression = Com_GetValue<uiAction_t*>(object, property);
852 expression = UI_AllocStaticStringCondition(*token);
853 if (!expression)
854 return false;
855 }
856 break;
857
858 case V_UI_DATAID:
859 {
860 *token = Com_EParse(text, errhead, objectName);
861 if (!*text)
862 return false;
863
864 int& dataId = Com_GetValue<int>(object, property);
865 dataId = UI_GetDataIDByName(*token);
866 if (dataId < 0) {
867 Com_Printf("UI_ParseProperty: Could not find shared data ID '%s' (%s@%s)\n",
868 *token, objectName, property->string);
869 return false;
870 }
871 }
872 break;
873
874 default:
875 Com_Printf("UI_ParseProperty: unknown property type '%d' (0x%X) (%s@%s)\n",
876 property->type, property->type, objectName, property->string);
877 return false;
878 }
879 break;
880
881 default:
882 Com_Printf("UI_ParseProperties: unknown property type '%d' (0x%X) (%s@%s)\n",
883 property->type, property->type, objectName, property->string);
884 return false;
885 }
886
887 return true;
888}
889
890static bool UI_ParseFunction (uiNode_t* node, const char** text, const char** token)
891{
892 uiAction_t** action;
893 assert(UI_Node_IsFunction(node));
894
895 action = &node->onClick;
896 *action = UI_ParseActionList(node, text, token);
897 if (*action == nullptr)
898 return false;
899
900 return (*token)[0] == '}';
901}
902
920static bool UI_ParseNodeProperties (uiNode_t* node, const char** text, const char** token)
921{
922 const char* errhead = "UI_ParseNodeProperties: unexpected end of file (node";
923 bool nextTokenAlreadyRead = false;
924
925 if ((*token)[0] != '{')
926 nextTokenAlreadyRead = true;
927
928 do {
929 const value_t* val;
930 int result;
931
932 /* get new token */
933 if (!nextTokenAlreadyRead) {
934 *token = Com_EParse(text, errhead, node->name);
935 if (!*text)
936 return false;
937 } else {
938 nextTokenAlreadyRead = false;
939 }
940
941 /* is finished */
942 if ((*token)[0] == '}')
943 break;
944
945 /* find the property */
946 val = UI_GetPropertyFromBehaviour(node->behaviour, *token);
947 if (!val) {
948 /* unknown token, print message and continue */
949 Com_Printf("UI_ParseNodeProperties: unknown property \"%s\", node ignored (node %s)\n",
950 *token, UI_GetPath(node));
951 return false;
952 }
953
954 /* get parameter values */
955 result = UI_ParseProperty(node, val, node->name, text, token);
956 if (!result) {
957 Com_Printf("UI_ParseNodeProperties: Problem with parsing of node property '%s@%s'. See upper\n",
958 UI_GetPath(node), val->string);
959 return false;
960 }
961 } while (*text);
962
963 return true;
964}
965
978static bool UI_ParseNodeBody (uiNode_t* node, const char** text, const char** token, const char* errhead)
979{
980 bool result = true;
981
982 if ((*token)[0] != '{') {
983 /* read the body block start */
984 *token = Com_EParse(text, errhead, node->name);
985 if (!*text)
986 return false;
987 if ((*token)[0] != '{') {
988 Com_Printf("UI_ParseNodeBody: node doesn't have body, token '%s' read (node \"%s\")\n", *token, UI_GetPath(node));
989 ui_global.numNodes--;
990 return false;
991 }
992 }
993
994 /* functions are a special case */
995 if (UI_Node_IsFunction(node)) {
996 result = UI_ParseFunction(node, text, token);
997 } else {
998
999 /* check the content */
1000 *token = Com_EParse(text, errhead, node->name);
1001 if (!*text)
1002 return false;
1003
1004 if ((*token)[0] == '{') {
1005 /* we have a special block for properties */
1006 result = UI_ParseNodeProperties(node, text, token);
1007 if (!result)
1008 return false;
1009
1010 /* move token over the next node behaviour */
1011 *token = Com_EParse(text, errhead, node->name);
1012 if (!*text)
1013 return false;
1014
1015 /* and then read all nodes */
1016 while ((*token)[0] != '}') {
1017 uiNode_t* newNode = UI_ParseNode(node, text, token, errhead);
1018 if (!newNode)
1019 return false;
1020
1021 *token = Com_EParse(text, errhead, node->name);
1022 if (*text == nullptr)
1023 return false;
1024 }
1025 } else if (UI_GetPropertyFromBehaviour(node->behaviour, *token)) {
1026 /* we should have a block with properties only */
1027 result = UI_ParseNodeProperties(node, text, token);
1028 } else {
1029 /* we should have a block with nodes only */
1030 while ((*token)[0] != '}') {
1031 uiNode_t* newNode = UI_ParseNode(node, text, token, errhead);
1032 if (!newNode)
1033 return false;
1034
1035 *token = Com_EParse(text, errhead, node->name);
1036 if (*text == nullptr)
1037 return false;
1038 }
1039 }
1040 }
1041 if (!result) {
1042 Com_Printf("UI_ParseNodeBody: node with bad body ignored (node \"%s\")\n", UI_GetPath(node));
1043 ui_global.numNodes--;
1044 return false;
1045 }
1046
1047 /* already check on UI_ParseNodeProperties */
1048 assert((*token)[0] == '}');
1049 return true;
1050}
1051
1059static uiNode_t* UI_ParseNode (uiNode_t* parent, const char** text, const char** token, const char* errhead)
1060{
1061 uiNode_t* node = nullptr;
1062 uiBehaviour_t* behaviour;
1063 uiNode_t* component = nullptr;
1064
1065 /* get the behaviour */
1066 behaviour = UI_GetNodeBehaviour(*token);
1067 if (!behaviour) {
1068 component = UI_GetComponent(*token);
1069 }
1070 if (behaviour == nullptr && component == nullptr) {
1071 Com_Printf("UI_ParseNode: node behaviour/component '%s' doesn't exist (%s)\n", *token, UI_GetPath(parent));
1072 return nullptr;
1073 }
1074
1075 /* get the name */
1076 *token = Com_EParse(text, errhead, "");
1077 if (!*text)
1078 return nullptr;
1079 if (!UI_TokenIsName(*token, Com_GetType(text) == TT_QUOTED_WORD)) {
1080 Com_Printf("UI_ParseNode: \"%s\" is not a well formed node name ([a-zA-Z_][a-zA-Z0-9_]*)\n", *token);
1081 return nullptr;
1082 }
1083 if (UI_TokenIsReserved(*token)) {
1084 Com_Printf("UI_ParseNode: \"%s\" is a reserved token, we can't call a node with it\n", *token);
1085 return nullptr;
1086 }
1087
1088 /* test if node already exists */
1089 /* Already existing node should only come from inherited node, we should not have 2 definitions of the same node into the same window. */
1090 if (parent)
1091 node = UI_GetNode(parent, *token);
1092
1093 /* reuse a node */
1094 if (node) {
1095 const uiBehaviour_t* test = (behaviour != nullptr) ? behaviour : (component != nullptr) ? component->behaviour : nullptr;
1096 if (node->behaviour != test) {
1097 Com_Printf("UI_ParseNode: we can't change node type (node \"%s\")\n", UI_GetPath(node));
1098 return nullptr;
1099 }
1100 Com_DPrintf(DEBUG_CLIENT, "... over-riding node %s\n", UI_GetPath(node));
1101
1102 }
1103 /* else initialize a component */
1104 else if (component) {
1105 node = UI_CloneNode(component, nullptr, true, *token, true);
1106 if (parent) {
1107 UI_AppendNode(parent, node);
1108 UI_UpdateRoot(node, parent->root);
1109 }
1110 }
1111 /* else initialize a new node */
1112 else {
1113 node = UI_AllocNode(*token, behaviour->name, true);
1114 if (parent) {
1115 UI_AppendNode(parent, node);
1116 }
1117 }
1118
1119 /* get body */
1120 const bool result = UI_ParseNodeBody(node, text, token, errhead);
1121 if (!result)
1122 return nullptr;
1123
1124 /* validate properties */
1125 UI_Node_Loaded(node);
1126
1127 return node;
1128}
1129
1134bool UI_ParseUIModel (const char* name, const char** text)
1135{
1136 const char* errhead = "UI_ParseUIModel: unexpected end of file (names ";
1137
1138 /* search for a UI models with same name */
1139 for (int i = 0; i < ui_global.numModels; i++)
1140 if (Q_streq(ui_global.models[i].id, name)) {
1141 Com_Printf("UI_ParseUIModel: menu_model \"%s\" with same name found, second ignored\n", name);
1142 return false;
1143 }
1144
1145 if (ui_global.numModels >= UI_MAX_MODELS) {
1146 Com_Printf("UI_ParseUIModel: Max UI models reached\n");
1147 return false;
1148 }
1149
1150 /* initialize the model */
1151 uiModel_t* model = &ui_global.models[ui_global.numModels];
1152 OBJZERO(*model);
1153
1154 Vector4Set(model->color, 1, 1, 1, 1);
1155
1156 model->id = Mem_PoolStrDup(name, ui_sysPool, 0);
1157 Com_DPrintf(DEBUG_CLIENT, "Found UI model %s (%i)\n", model->id, ui_global.numModels);
1158
1159 /* get it's body */
1160 const char* token = Com_Parse(text);
1161
1162 if (!*text || token[0] != '{') {
1163 Com_Printf("UI_ParseUIModel: Model \"%s\" without body ignored\n", model->id);
1164 return false;
1165 }
1166
1167 ui_global.numModels++;
1168
1169 do {
1170 const value_t* v = nullptr;
1171 /* get the name type */
1172 token = Com_EParse(text, errhead, name);
1173 if (!*text)
1174 return false;
1175 if (token[0] == '}')
1176 break;
1177
1179 if (!v) {
1180 Com_Printf("UI_ParseUIModel: unknown token \"%s\" ignored (UI model %s)\n", token, name);
1181 return false;
1182 }
1183
1184 if (v->type == V_NULL) {
1185 if (Q_streq(v->string, "need")) {
1186 token = Com_EParse(text, errhead, name);
1187 if (!*text)
1188 return false;
1189 if (model->next != nullptr)
1190 Sys_Error("UI_ParseUIModel: second 'need' token found in model %s", name);
1191 model->next = UI_GetUIModel(token);
1192 if (!model->next)
1193 Com_Printf("Could not find UI model %s\n", token);
1194 }
1195 } else {
1196 token = Com_EParse(text, errhead, name);
1197 if (!*text)
1198 return false;
1199 switch (v->type) {
1200 case V_HUNK_STRING:
1201 Mem_PoolStrDupTo(token, &Com_GetValue<char*>(model, v), ui_sysPool, 0);
1202 break;
1203 default:
1204 Com_EParseValue(model, token, v->type, v->ofs, v->size);
1205 break;
1206 }
1207 }
1208 } while (*text);
1209
1210 return true;
1211}
1212
1213bool UI_ParseSprite (const char* name, const char** text)
1214{
1215 uiSprite_t* icon;
1216 const char* token;
1217
1218 /* search for icons with same name */
1219 icon = UI_AllocStaticSprite(name);
1220
1221 /* get it's body */
1222 token = Com_Parse(text);
1223 assert(token[0] == '{');
1224
1225 /* read properties */
1226 while (true) {
1227 const value_t* property;
1228
1229 token = Com_Parse(text);
1230 if (*text == nullptr)
1231 return false;
1232
1233 if (token[0] == '}')
1234 break;
1235
1236 property = UI_FindPropertyByName(ui_spriteProperties, token);
1237 if (!property) {
1238 Com_Printf("UI_ParseIcon: unknown options property: '%s' - ignore it\n", token);
1239 return false;
1240 }
1241
1242 /* get parameter values */
1243 const bool result = UI_ParseProperty(icon, property, icon->name, text, &token);
1244 if (!result) {
1245 Com_Printf("UI_ParseIcon: Parsing for sprite '%s'. See upper\n", icon->name);
1246 return false;
1247 }
1248 }
1249
1250 return true;
1251}
1252
1261bool UI_ParseComponent (const char* type, const char* name, const char** text)
1262{
1263 const char* errhead = "UI_ParseComponent: unexpected end of file (component";
1264 const char* token;
1265
1266 if (!Q_streq(type, "component")) {
1267 Com_Error(ERR_FATAL, "UI_ParseComponent: \"component\" expected but \"%s\" found.\n", type);
1268 return false; /* never reached */
1269 }
1270
1271 /* check the name */
1272 if (!UI_TokenIsName(name, false)) {
1273 Com_Printf("UI_ParseNode: \"%s\" is not a well formed node name ([a-zA-Z_][a-zA-Z0-9_]*)\n", name);
1274 return false;
1275 }
1276 if (UI_TokenIsReserved(name)) {
1277 Com_Printf("UI_ParseNode: \"%s\" is a reserved token, we can't call a node with it\n", name);
1278 return false;
1279 }
1280
1281 token = Com_EParse(text, errhead, "");
1282 if (text == nullptr)
1283 return false;
1284
1285 /* get keyword */
1286 if (!Q_streq(token, "extends")) {
1287 Com_Printf("UI_ParseComponent: \"extends\" expected but \"%s\" found (component %s)\n", token, name);
1288 return false;
1289 }
1290 token = Com_EParse(text, errhead, "");
1291 if (text == nullptr)
1292 return false;
1293
1294 /* initialize component */
1295 uiNode_t* component = nullptr;
1296 const uiBehaviour_t* behaviour = UI_GetNodeBehaviour(token);
1297 if (behaviour) {
1298 /* initialize a new node from behaviour */
1299 component = UI_AllocNode(name, behaviour->name, false);
1300 }
1301 else {
1302 const uiNode_t* inheritedComponent = UI_GetComponent(token);
1303 if (inheritedComponent) {
1304 /* initialize from a component */
1305 component = UI_CloneNode(inheritedComponent, nullptr, true, name, false);
1306 } else {
1307 Com_Printf("UI_ParseComponent: node behaviour/component '%s' doesn't exists (component %s)\n", token, name);
1308 return false;
1309 }
1310 }
1311
1312 /* get body */
1313 token = Com_EParse(text, errhead, "");
1314 if (!*text)
1315 return false;
1316 bool result = UI_ParseNodeBody(component, text, &token, errhead);
1317 if (!result)
1318 return false;
1319
1320 /* validate properties */
1321 UI_Node_Loaded(component);
1322
1323 UI_InsertComponent(component);
1324 return true;
1325}
1326
1327
1336bool UI_ParseWindow (const char* type, const char* name, const char** text)
1337{
1338 const char* errhead = "UI_ParseWindow: unexpected end of file (window";
1339 uiNode_t* window;
1340 const char* token;
1341 int i;
1342
1343 if (!Q_streq(type, "window")) {
1344 Com_Error(ERR_FATAL, "UI_ParseWindow: '%s %s' is not a window node\n", type, name);
1345 return false; /* never reached */
1346 }
1347
1349 Com_Printf("UI_ParseWindow: \"%s\" is not a well formed node name ([a-zA-Z_][a-zA-Z0-9_]*)\n", name);
1350 return false;
1351 }
1352 if (UI_TokenIsReserved(name)) {
1353 Com_Printf("UI_ParseWindow: \"%s\" is a reserved token, we can't call a node with it (node \"%s\")\n", name, name);
1354 return false;
1355 }
1356
1357 /* search for windows with same name */
1358 for (i = 0; i < ui_global.numWindows; i++) {
1359 if (Q_streq(name, ui_global.windows[i]->name)) {
1360 break;
1361 }
1362 }
1363
1364 if (i < ui_global.numWindows) {
1365 Com_Printf("UI_ParseWindow: %s \"%s\" with same name found, second ignored\n", type, name);
1366 }
1367
1368 if (ui_global.numWindows >= UI_MAX_WINDOWS) {
1369 Com_Error(ERR_FATAL, "UI_ParseWindow: max windows exceeded (%i) - ignore '%s'\n", UI_MAX_WINDOWS, name);
1370 return false; /* never reached */
1371 }
1372
1373 /* get window body */
1374 token = Com_Parse(text);
1375
1376 /* does this window inherit data from another window? */
1377 if (Q_streq(token, "extends")) {
1378 uiNode_t* superWindow;
1379 token = Com_Parse(text);
1380 superWindow = UI_GetWindow(token);
1381 if (superWindow == nullptr)
1382 Sys_Error("Could not get the super window \"%s\"", token);
1383 window = UI_CloneNode(superWindow, nullptr, true, name, true);
1384 token = Com_Parse(text);
1385 } else {
1386 window = UI_AllocNode(name, type, true);
1387 window->root = window;
1388 }
1389
1390 UI_InsertWindow(window);
1391
1392 /* parse it's body */
1393 bool result = UI_ParseNodeBody(window, text, &token, errhead);
1394 if (!result) {
1395 Com_Error(ERR_FATAL, "UI_ParseWindow: window \"%s\" has a bad body\n", window->name);
1396 }
1397
1398 UI_Node_Loaded(window);
1399 return true;
1400}
1401
1406const char* UI_GetReferenceString (const uiNode_t* const node, const char* ref)
1407{
1408 if (!ref)
1409 return nullptr;
1410
1411 /* its a cvar */
1412 if (ref[0] != '*')
1413 return CL_Translate(ref);
1414
1415 /* get the reference and the name */
1416 const char* token = Com_MacroExpandString(ref);
1417 if (token)
1418 return CL_Translate(token);
1419
1420 /* skip the star */
1421 token = ref + 1;
1422 if (token[0] == '\0')
1423 return nullptr;
1424
1425 Sys_Error("UI_GetReferenceString: unknown reference %s", token);
1426}
1427
1434float UI_GetReferenceFloat (const uiNode_t* const node, const void* ref)
1435{
1436 if (!ref)
1437 return 0.0;
1438 if (char const* const token = Q_strstart((char const*)ref, "*")) {
1439 if (token[0] == '\0')
1440 return 0.0;
1441
1442 if (char const* const cvar = Q_strstart(token, "cvar:")) {
1443 return Cvar_GetValue(cvar);
1444 }
1445 }
1446
1447 /* just get the data */
1448 return *(const float*) ref;
1449}
const char * CL_Translate(const char *t)
Primary header for client.
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition common.cpp:440
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
const char * Com_MacroExpandString(const char *text)
Expands strings with cvar values that are dereferenced by a '*cvar'.
Definition common.cpp:647
#define ERR_FATAL
Definition common.h:210
float Cvar_GetValue(const char *varName)
Returns the float value of a cvar.
Definition cvar.cpp:125
#define DEBUG_CLIENT
Definition defines.h:59
void Sys_Error(const char *error,...)
Definition g_main.cpp:421
voidpf void uLong size
Definition ioapi.h:42
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
#define Mem_PoolStrDup(in, pool, tagNum)
Definition mem.h:50
#define Mem_PoolStrDupTo(in, out, pool, tagNum)
Definition mem.h:49
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition parse.cpp:107
void Com_UnParseLastToken(void)
Put back the last token into the parser The next call of Com_Parse will return the same token again.
Definition parse.cpp:42
Com_TokenType_t Com_GetType(const char **data_p)
Get the current token type.
Definition parse.cpp:60
Shared parsing functions.
@ TT_QUOTED_WORD
Definition parse.h:43
QGL_EXTERN GLuint count
Definition r_gl.h:99
QGL_EXTERN int GLboolean GLfloat * v
Definition r_gl.h:120
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLint GLenum type
Definition r_gl.h:94
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
const char * Com_EParse(const char **text, const char *errhead, const char *errinfo, char *target, size_t size)
Parsing function that prints an error message when there is no text in the buffer.
Definition scripts.cpp:277
const char * Com_GetLastParseError(void)
Definition scripts.cpp:428
resultStatus_t Com_ParseValue(void *base, const char *token, valueTypes_t type, int ofs, size_t size, size_t *writtenBytes)
Parse a value from a string.
Definition scripts.cpp:656
void * Com_AlignPtr(const void *memory, valueTypes_t type)
Align a memory to use a natural address for the data type we will write.
Definition scripts.cpp:437
int Com_EParseValue(void *base, const char *token, valueTypes_t type, int ofs, size_t size)
Definition scripts.cpp:964
#define V_BASETYPEMASK
Allow to add extra bit into the type.
Definition scripts.h:41
T & Com_GetValue(void *const object, value_t const *const value)
Definition scripts.h:174
valueTypes_t
possible values for parsing functions
Definition scripts.h:48
@ V_TRANSLATION_STRING
Definition scripts.h:59
@ V_HUNK_STRING
Definition scripts.h:69
@ V_NULL
Definition scripts.h:49
@ V_STRING
Definition scripts.h:58
@ V_INT
Definition scripts.h:52
@ V_COLOR
Definition scripts.h:57
@ V_POS
Definition scripts.h:55
@ RESULT_OK
Definition scripts.h:187
#define Q_strcasecmp(a, b)
Definition shared.h:131
#define Q_streq(a, b)
Definition shared.h:136
#define OBJZERO(obj)
Definition shared.h:178
#define MAX_VAR
Definition shared.h:36
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition shared.cpp:587
Atomic element to store UI scripts The parser use this atom to translate script action into many tree...
Definition ui_actions.h:144
short type
Define the type of the element, it can be a command, an operator, or a value.
Definition ui_actions.h:149
uiTerminalActionData_t d1
Definition ui_actions.h:175
struct uiAction_t::@020173205255351022052355137266041366256354050344::@226100300324067003344030331332225043077332072062 terminal
Stores a terminal action (a value, which must be a leaf in the tree).
struct uiAction_s * next
Next element in the action list.
Definition ui_actions.h:183
struct uiAction_t::@020173205255351022052355137266041366256354050344::@051207210304220322206103241251135377014006203150 nonTerminal
Stores a none terminal action (a command or an operator).
uiTerminalActionData_t d2
Definition ui_actions.h:176
struct uiAction_s * right
Definition ui_actions.h:166
union uiAction_t::@020173205255351022052355137266041366256354050344 d
Stores data about the action.
struct uiAction_s * left
Definition ui_actions.h:165
node behaviour, how a node work
const char * name
struct uiExcludeRect_s * next
Definition ui_nodes.h:47
Model that have more than one part (top and down part of an aircraft).
struct uiModel_s * next
vec4_t color
Atomic structure used to define most of the UI.
Definition ui_nodes.h:80
uiBehaviour_t * behaviour
Definition ui_nodes.h:83
uiExcludeRect_t * firstExcludeRect
Definition ui_nodes.h:116
char name[MAX_VAR]
Definition ui_nodes.h:82
struct uiAction_s * onClick
Definition ui_nodes.h:135
uiNode_t * root
Definition ui_nodes.h:93
char name[MAX_VAR]
Definition ui_sprite.h:42
size_t ofs
Definition scripts.h:170
const char * string
Definition scripts.h:168
size_t size
Definition scripts.h:171
valueTypes_t type
Definition scripts.h:169
float vec_t
Definition ufotypes.h:37
vec_t vec4_t[4]
Definition ufotypes.h:40
vec_t vec2_t[2]
Definition ufotypes.h:38
int UI_GetActionTokenType(const char *token, int group)
return an action type from a token, and a group
bool UI_IsInjectedString(const char *string)
Test if a string use an injection syntax.
@ EA_CMD
Definition ui_actions.h:44
@ EA_VALUE_PATHPROPERTY_WITHINJECTION
Definition ui_actions.h:104
@ EA_VALUE_STRING
Definition ui_actions.h:95
@ EA_VALUE_PATHNODE
Definition ui_actions.h:101
@ EA_ELSE
Definition ui_actions.h:48
@ EA_CALL
Definition ui_actions.h:45
@ EA_ASSIGN
Definition ui_actions.h:46
@ EA_ELIF
Definition ui_actions.h:49
@ EA_VALUE_CVARNAME
Definition ui_actions.h:99
@ EA_DELETE
Definition ui_actions.h:51
@ EA_FORCHILDIN
Definition ui_actions.h:55
@ EA_VALUE_RAW
Definition ui_actions.h:98
@ EA_VALUE_PATHPROPERTY
Definition ui_actions.h:103
@ EA_VALUE_CVARNAME_WITHINJECTION
Definition ui_actions.h:100
@ EA_NULL
Definition ui_actions.h:34
@ EA_VALUE_STRING_WITHINJECTION
Definition ui_actions.h:96
@ EA_IF
Definition ui_actions.h:47
@ EA_WHILE
Definition ui_actions.h:50
@ EA_ACTION
Definition ui_actions.h:43
@ EA_VALUE_PATHNODE_WITHINJECTION
Definition ui_actions.h:102
const value_t * UI_GetPropertyFromBehaviour(const uiBehaviour_t *behaviour, const char *name)
Get a property from a behaviour or his inheritance It use a dichotomic search.
uiNode_t * UI_GetComponent(const char *name)
Searches all components for the specified one.
void UI_InsertComponent(uiNode_t *component)
Add a new component to the list of all components.
int UI_GetDataIDByName(const char *name)
Return a dataId by name.
Definition ui_data.cpp:102
Data and interface to share data.
uiAction_t * UI_AllocStaticStringCondition(const char *description)
Allocate and initialize an expression according to a string.
uiAction_t * UI_ParseExpression(const char **text)
Internal data use by the UI package.
void * UI_AllocHunkMemory(size_t size, int align, bool reset)
Definition ui_main.cpp:126
memPool_t * ui_sysPool
Definition ui_main.cpp:42
uiGlobal_t ui_global
Definition ui_main.cpp:38
#define UI_MAX_WINDOWS
Definition ui_internal.h:29
#define STRUCT_MEMORY_ALIGN
#define UI_MAX_ACTIONS
Definition ui_internal.h:32
bool UI_Node_IsFunction(uiNode_t const *node)
Definition ui_node.cpp:85
void UI_UpdateRoot(uiNode_t *node, uiNode_t *newRoot)
Definition ui_node.cpp:853
void UI_Node_Loaded(uiNode_t *node)
Definition ui_node.cpp:214
void UI_AppendNode(uiNode_t *const parent, uiNode_t *newNode)
add a node at the end of the node child
Definition ui_node.cpp:868
uiNode_t * UI_GetNode(const uiNode_t *node, const char *name)
Search a child node by given name.
Definition ui_node.cpp:714
C interface to allow to access to cpp node code.
uiModel_t * UI_GetUIModel(const char *modelName)
Returns pointer to UI model.
#define UI_MAX_MODELS
uiBehaviour_t * UI_GetNodeBehaviour(const char *name)
Return a node behaviour by name.
Definition ui_nodes.cpp:559
uiNode_t * UI_AllocNode(const char *name, const char *type, bool isDynamic)
Allocate a node into the UI memory.
Definition ui_nodes.cpp:381
uiNode_t * UI_CloneNode(const uiNode_t *node, uiNode_t *newWindow, bool recursive, const char *newName, bool isDynamic)
Clone a node.
Definition ui_nodes.cpp:409
const char * UI_GetPath(const uiNode_t *node)
Return a path from a window to a node.
Definition ui_nodes.cpp:174
static bool UI_ParseNodeProperties(uiNode_t *node, const char **text, const char **token)
parse all sequencial properties into a block
Definition ui_parse.cpp:920
float UI_GetReferenceFloat(const uiNode_t *const node, const void *ref)
Returns the value of the reference variable.
static bool UI_ParseEventProperty(uiNode_t *node, const value_t *event, const char **text, const char **token, const char *errhead)
Definition ui_parse.cpp:668
const char * UI_GetReferenceString(const uiNode_t *const node, const char *ref)
const value_t * UI_FindPropertyByName(const value_t *propertyList, const char *name)
Find a value_t by name into a array of value_t.
Definition ui_parse.cpp:154
bool UI_ParseWindow(const char *type, const char *name, const char **text)
Parse a window.
static bool UI_TokenIsValue(const char *name, bool isQuoted)
Definition ui_parse.cpp:93
static bool UI_ParseNodeBody(uiNode_t *node, const char **text, const char **token, const char *errhead)
Read a node body.
Definition ui_parse.cpp:978
static const value_t uiModelProperties[]
valid properties for a UI model definition
Definition ui_parse.cpp:51
static uiAction_t * UI_ParseActionList(uiNode_t *node, const char **text, const char **token)
Parse actions and return action list.
Definition ui_parse.cpp:427
static bool UI_ParseSetAction(uiNode_t *node, uiAction_t *action, const char **text, const char **token, const char *errhead)
Parser for setter command.
Definition ui_parse.cpp:276
char * UI_AllocStaticString(const char *string, int size)
Allocate a string into the UI static memory.
Definition ui_parse.cpp:204
static bool UI_ParseFunction(uiNode_t *node, const char **text, const char **token)
Definition ui_parse.cpp:890
static bool UI_ParseCallAction(uiNode_t *node, uiAction_t *action, const char **text, const char **token, const char *errhead)
Parser for call command.
Definition ui_parse.cpp:361
static bool UI_ParseProperty(void *object, const value_t *property, const char *objectName, const char **text, const char **token)
Parse a property value.
Definition ui_parse.cpp:698
vec4_t * UI_AllocStaticColor(int count)
Allocate a color into the UI static memory.
Definition ui_parse.cpp:187
static bool UI_ParseExcludeRect(uiNode_t *node, const char **text, const char **token, const char *errhead)
Definition ui_parse.cpp:623
bool UI_ParseSprite(const char *name, const char **text)
bool UI_InitRawActionValue(uiAction_t *action, uiNode_t *node, const value_t *property, const char *string)
Definition ui_parse.cpp:238
static char const *const reservedTokens[]
reserved token preventing calling a node with it
Definition ui_parse.cpp:66
bool UI_ParseUIModel(const char *name, const char **text)
parses the models.ufo and all files where UI models (menu_model) are defined
bool UI_TokenIsName(const char *name, bool isQuoted)
Definition ui_parse.cpp:126
uiAction_t * UI_AllocStaticAction(void)
Allocate an action.
Definition ui_parse.cpp:221
float * UI_AllocStaticFloat(int count)
Allocate a float into the UI static memory.
Definition ui_parse.cpp:171
static uiNode_t * UI_ParseNode(uiNode_t *parent, const char **text, const char **token, const char *errhead)
parse a node
bool UI_ParseComponent(const char *type, const char *name, const char **text)
Parse a component.
bool UI_TokenIsReserved(const char *name)
Definition ui_parse.cpp:82
#define V_UI_SPRITEREF
Definition ui_parse.h:56
#define V_UI_DATAID
Definition ui_parse.h:58
#define V_UI_EXCLUDERECT
Definition ui_parse.h:55
#define V_UI_REF
Definition ui_parse.h:60
#define V_UI_ACTION
Definition ui_parse.h:54
#define V_UI_CVAR
Definition ui_parse.h:59
#define V_UI
Definition ui_parse.h:52
#define V_UI_IF
Definition ui_parse.h:57
#define V_NOT_UI
Definition ui_parse.h:53
#define V_UI_MASK
Definition ui_parse.h:51
const value_t ui_spriteProperties[]
Definition ui_sprite.cpp:31
uiSprite_t * UI_AllocStaticSprite(const char *name)
Allocate an sprite to the UI static memory.
uiSprite_t * UI_GetSpriteByName(const char *name)
Return an sprite by is name.
void UI_InsertWindow(uiNode_t *window)
Add a new window to the list of all windows.
uiNode_t * UI_GetWindow(const char *name)
Searches all windows for the specified one.
const char * constString
Definition ui_actions.h:127
#define Vector4Set(v, r, g, b, a)
Definition vector.h:62