UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ui_parse.cpp
Go to the documentation of this file.
1 
8 /*
9 Copyright (C) 2002-2020 UFO: Alien Invasion.
10 
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 
20 See the GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, 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"
38 #include "node/ui_node_selectbox.h"
41 
42 #include "../../shared/parse.h"
43 #include "../cl_language.h"
44 
46 static bool UI_ParseProperty(void* object, const value_t* property, const char* objectName, const char** text, const char** token);
47 static uiAction_t* UI_ParseActionList(uiNode_t* node, const char** text, const char** token);
48 static uiNode_t* UI_ParseNode(uiNode_t* parent, const char** text, const char** token, const char* errhead);
49 
51 static 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 
66 static 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 
82 bool 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 
93 static 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 
126 bool 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 
154 const 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 
204 char* 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 {
224  Com_Error(ERR_FATAL, "UI_AllocAction: Too many UI actions");
226 }
227 
238 bool 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  }
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 
276 static 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 */
304  if (type == EA_VALUE_CVARNAME || type == EA_VALUE_CVARNAME_WITHINJECTION) {
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 
361 static 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 
427 static 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 
455  type = UI_GetActionTokenType(*token, EA_ACTION);
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;
569  if (type != EA_VALUE_PATHNODE && type != EA_VALUE_PATHNODE_WITHINJECTION) {
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 
623 static 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 
668 static 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 
698 static 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 */
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 */
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 */
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 
890 static 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 
920 static 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 
978 static 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));
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 
1059 static 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 
1134 bool 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 
1146  Com_Printf("UI_ParseUIModel: Max UI models reached\n");
1147  return false;
1148  }
1149 
1150  /* initialize the model */
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 
1178  v = UI_FindPropertyByName(uiModelProperties, token);
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 
1213 bool 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 
1261 bool 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 
1336 bool 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 
1348  if (!UI_TokenIsName(name, Com_GetType(text) == TT_QUOTED_WORD)) {
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 
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 
1406 const 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 
1434 float 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 }
int numModels
Definition: ui_internal.h:84
int numActions
Definition: ui_internal.h:81
vec4_t * UI_AllocStaticColor(int count)
Allocate a color into the UI static memory.
Definition: ui_parse.cpp:187
const char * Com_GetLastParseError(void)
Definition: scripts.cpp:431
bool UI_IsInjectedString(const char *string)
Test if a string use an injection syntax.
Definition: ui_actions.cpp:751
uiAction_t * UI_AllocStaticAction(void)
Allocate an action.
Definition: ui_parse.cpp:221
static bool UI_ParseFunction(uiNode_t *node, const char **text, const char **token)
Definition: ui_parse.cpp:890
struct uiAction_s::@14::@16 terminal
Stores a terminal action (a value, which must be a leaf in the tree)
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
#define UI_MAX_ACTIONS
Definition: ui_internal.h:32
void * UI_AllocHunkMemory(size_t size, int align, bool reset)
Definition: ui_main.cpp:126
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
uiAction_t * UI_AllocStaticStringCondition(const char *description)
Allocate and initialize an expression according to a string.
void UI_InsertWindow(uiNode_t *window)
Add a new window to the list of all windows.
Definition: ui_windows.cpp:616
valueTypes_t
possible values for parsing functions
Definition: scripts.h:48
static uiNode_t * UI_ParseNode(uiNode_t *parent, const char **text, const char **token, const char *errhead)
parse a node
Definition: ui_parse.cpp:1059
uiGlobal_t ui_global
Definition: ui_main.cpp:38
bool UI_ParseComponent(const char *type, const char *name, const char **text)
Parse a component.
Definition: ui_parse.cpp:1261
#define V_BASETYPEMASK
Allow to add extra bit into the type.
Definition: scripts.h:41
const char * name
Definition: ui_behaviour.h:41
void UI_UpdateRoot(uiNode_t *node, uiNode_t *newRoot)
Definition: ui_node.cpp:841
char * id
Definition: ui_node_model.h:48
uiNode_t * UI_GetComponent(const char *name)
Searches all components for the specified one.
float * UI_AllocStaticFloat(int count)
Allocate a float into the UI static memory.
Definition: ui_parse.cpp:171
bool UI_TokenIsReserved(const char *name)
Definition: ui_parse.cpp:82
char name[MAX_VAR]
Definition: ui_nodes.h:82
uiBehaviour_t * behaviour
Definition: ui_nodes.h:83
float vec_t
Definition: ufotypes.h:37
static bool UI_TokenIsValue(const char *name, bool isQuoted)
Definition: ui_parse.cpp:93
#define UI_MAX_MODELS
Definition: ui_node_model.h:44
#define V_UI_SPRITEREF
Definition: ui_parse.h:56
uiExcludeRect_t * firstExcludeRect
Definition: ui_nodes.h:116
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
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
void UI_AppendNode(uiNode_t *const parent, uiNode_t *newNode)
add a node at the end of the node child
Definition: ui_node.cpp:856
valueTypes_t type
Definition: scripts.h:170
uiModel_t models[UI_MAX_MODELS]
Definition: ui_internal.h:83
uiAction_t * UI_ParseExpression(const char **text)
union uiAction_s::@14 d
Stores data about the action.
struct uiAction_s * onClick
Definition: ui_nodes.h:135
uiAction_t actions[UI_MAX_ACTIONS]
Definition: ui_internal.h:80
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.
#define ERR_FATAL
Definition: common.h:210
bool UI_ParseUIModel(const char *name, const char **text)
parses the models.ufo and all files where UI models (menu_model) are defined
Definition: ui_parse.cpp:1134
#define Mem_PoolStrDupTo(in, out, pool, tagNum)
Definition: mem.h:49
int UI_GetDataIDByName(const char *name)
Return a dataId by name.
Definition: ui_data.cpp:102
Internal data use by the UI package.
C interface to allow to access to cpp node code.
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
uiNode_t * UI_AllocNode(const char *name, const char *type, bool isDynamic)
Allocate a node into the UI memory.
Definition: ui_nodes.cpp:381
uiSprite_t * UI_AllocStaticSprite(const char *name)
Allocate an sprite to the UI static memory.
Definition: ui_sprite.cpp:130
#define V_UI
Definition: ui_parse.h:52
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define V_UI_REF
Definition: ui_parse.h:60
uiNode_t * root
Definition: ui_nodes.h:93
struct uiAction_s::@14::@15 nonTerminal
Stores a none terminal action (a command or an operator)
#define DEBUG_CLIENT
Definition: defines.h:59
int UI_GetActionTokenType(const char *token, int group)
return an action type from a token, and a group
Definition: ui_actions.cpp:113
GLsizei size
Definition: r_gl.h:152
#define STRUCT_MEMORY_ALIGN
Definition: ui_internal.h:104
#define V_UI_CVAR
Definition: ui_parse.h:59
#define OBJZERO(obj)
Definition: shared.h:178
bool UI_TokenIsName(const char *name, bool isQuoted)
Definition: ui_parse.cpp:126
#define MAX_VAR
Definition: shared.h:36
float Cvar_GetValue(const char *varName)
Returns the float value of a cvar.
Definition: cvar.cpp:125
#define Vector4Set(v, r, g, b, a)
Definition: vector.h:62
static char const *const reservedTokens[]
reserved token preventing calling a node with it
Definition: ui_parse.cpp:66
const char * Com_MacroExpandString(const char *text)
Expands strings with cvar values that are dereferenced by a '*cvar'.
Definition: common.cpp:607
void UI_Node_Loaded(uiNode_t *node)
Definition: ui_node.cpp:214
bool UI_ParseWindow(const char *type, const char *name, const char **text)
Parse a window.
Definition: ui_parse.cpp:1336
const char * UI_GetPath(const uiNode_t *node)
Return a path from a window to a node.
Definition: ui_nodes.cpp:174
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
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition: shared.cpp:587
#define V_UI_IF
Definition: ui_parse.h:57
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
Data and interface to share data.
const char * UI_GetReferenceString(const uiNode_t *const node, const char *ref)
Definition: ui_parse.cpp:1406
#define Q_strcasecmp(a, b)
Definition: shared.h:131
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
Atomic structure used to define most of the UI.
Definition: ui_nodes.h:80
const char * string
Definition: scripts.h:169
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:659
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
uiNode_t * windows[UI_MAX_WINDOWS]
Definition: ui_internal.h:68
bool UI_ParseSprite(const char *name, const char **text)
Definition: ui_parse.cpp:1213
float UI_GetReferenceFloat(const uiNode_t *const node, const void *ref)
Returns the value of the reference variable.
Definition: ui_parse.cpp:1434
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
uiModel_t * UI_GetUIModel(const char *modelName)
Returns pointer to UI model.
int numNodes
Definition: ui_internal.h:66
QGL_EXTERN GLuint count
Definition: r_gl.h:99
size_t ofs
Definition: scripts.h:171
const value_t ui_spriteProperties[]
Definition: ui_sprite.cpp:31
uiNode_t * UI_GetWindow(const char *name)
Searches all windows for the specified one.
Definition: ui_windows.cpp:567
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
int Com_EParseValue(void *base, const char *token, valueTypes_t type, int ofs, size_t size)
Definition: scripts.cpp:978
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
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
Definition: scripts.h:49
int numWindows
Definition: ui_internal.h:69
vec4_t color
Definition: ui_node_model.h:56
QGL_EXTERN GLint i
Definition: r_gl.h:113
#define V_UI_EXCLUDERECT
Definition: ui_parse.h:55
const char * CL_Translate(const char *t)
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
uiNode_t * UI_GetNode(const uiNode_t *node, const char *name)
Search a child node by given name.
Definition: ui_node.cpp:702
node behaviour, how a node work
Definition: ui_behaviour.h:39
#define UI_MAX_WINDOWS
Definition: ui_internal.h:29
uiBehaviour_t * UI_GetNodeBehaviour(const char *name)
Return a node behaviour by name.
Definition: ui_nodes.cpp:559
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
bool UI_InitRawActionValue(uiAction_t *action, uiNode_t *node, const value_t *property, const char *string)
Definition: ui_parse.cpp:238
char name[MAX_VAR]
Definition: ui_sprite.h:42
#define V_UI_DATAID
Definition: ui_parse.h:58
Com_TokenType_t Com_GetType(const char **data_p)
Get the current token type.
Definition: parse.cpp:60
size_t size
Definition: scripts.h:172
struct uiAction_s * next
Next element in the action list.
Definition: ui_actions.h:183
vec_t vec2_t[2]
Definition: ufotypes.h:38
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
Definition: scripts.h:52
struct uiModel_s * next
Definition: ui_node_model.h:57
byte * curadata
Definition: ui_internal.h:74
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:440
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
memPool_t * ui_sysPool
Definition: ui_main.cpp:42
#define V_UI_ACTION
Definition: ui_parse.h:54
#define Q_streq(a, b)
Definition: shared.h:136
#define Mem_PoolStrDup(in, pool, tagNum)
Definition: mem.h:50
#define V_NOT_UI
Definition: ui_parse.h:53
Model that have more than one part (top and down part of an aircraft)
Definition: ui_node_model.h:47
bool UI_Node_IsFunction(uiNode_t const *node)
Definition: ui_node.cpp:85
uiSprite_t * UI_GetSpriteByName(const char *name)
Return an sprite by is name.
Definition: ui_sprite.cpp:115
#define V_UI_MASK
Definition: ui_parse.h:51
static const value_t uiModelProperties[]
valid properties for a UI model definition
Definition: ui_parse.cpp:51
struct uiExcludeRect_s * next
Definition: ui_nodes.h:47
uint8_t byte
Definition: ufotypes.h:34
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
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
char * UI_AllocStaticString(const char *string, int size)
Allocate a string into the UI static memory.
Definition: ui_parse.cpp:204
static bool UI_ParseExcludeRect(uiNode_t *node, const char **text, const char **token, const char *errhead)
Definition: ui_parse.cpp:623
short type
Define the type of the element, it can be a command, an operator, or a value.
Definition: ui_actions.h:149
Atomic element to store UI scripts The parser use this atom to translate script action into many tree...
Definition: ui_actions.h:144
Definition: scripts.h:55
void UI_InsertComponent(uiNode_t *component)
Add a new component to the list of all components.
vec_t vec4_t[4]
Definition: ufotypes.h:40