UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ui_behaviour.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 2002-2020 UFO: Alien Invasion.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 */
24 
25 #include "ui_main.h"
26 #include "ui_internal.h"
27 #include "ui_behaviour.h"
28 #include "ui_parse.h"
29 
30 #include "../../common/hashtable.h"
31 #include "../../common/scripts.h"
32 #include "../../common/scripts_lua.h"
33 #include "../../common/swig_lua_runtime.h"
34 
38 #define LOCAL_PROPERTY_SIZE 128
39 
40 
53 const struct value_s* UI_RegisterNodePropertyPosSize_ (uiBehaviour_t* behaviour, const char* name, int type, size_t pos, size_t size)
54 {
55  value_t* property = (value_t*) UI_AllocHunkMemory(sizeof(value_t), STRUCT_MEMORY_ALIGN, false);
56  if (property == nullptr)
57  Com_Error(ERR_FATAL, "UI_RegisterNodePropertyPosSize_: UI memory hunk exceeded - increase the size");
58 
59  if (type == V_STRING || type == V_LONGSTRING || type == V_CVAR_OR_LONGSTRING || V_CVAR_OR_STRING) {
60  size = 0;
61  }
62 
63  property->string = name;
64  property->type = (valueTypes_t) type;
65  property->ofs = pos;
66  property->size = size;
67 
68  if (behaviour->localProperties == nullptr) {
69  /* temporary memory allocation */
71  }
72  if (behaviour->propertyCount >= LOCAL_PROPERTY_SIZE - 1) {
73  Com_Error(ERR_FATAL, "UI_RegisterNodePropertyPosSize_: Property memory of behaviour %s is full.", behaviour->name);
74  }
75  behaviour->localProperties[behaviour->propertyCount++] = property;
76  behaviour->localProperties[behaviour->propertyCount] = nullptr;
77 
78  return property;
79 }
80 
88 const struct value_s* UI_RegisterNodeMethod (uiBehaviour_t* behaviour, const char* name, uiNodeMethod_t function)
89 {
90  return UI_RegisterNodePropertyPosSize_(behaviour, name, V_UI_NODEMETHOD, (size_t)function, 0);
91 }
92 
100 const value_t* UI_GetPropertyFromBehaviour (const uiBehaviour_t* behaviour, const char* name)
101 {
102  for (; behaviour; behaviour = behaviour->super) {
103  unsigned char min = 0;
104  unsigned char max = behaviour->propertyCount;
105 
106  while (min != max) {
107  const int mid = (min + max) >> 1;
108  const int diff = Q_strcasecmp(behaviour->localProperties[mid]->string, name);
109  assert(mid < max);
110  assert(mid >= min);
111 
112  if (diff == 0)
113  return behaviour->localProperties[mid];
114 
115  if (diff > 0)
116  max = mid;
117  else
118  min = mid + 1;
119  }
120  }
121  return nullptr;
122 }
123 
136 const value_t* UI_GetPropertyOrLuaMethod (const uiNode_t* node, const char* name, value_t *out) {
137  // first scan behaviour properties
138  const value_t* prop = UI_GetPropertyFromBehaviour (node->behaviour, name);
139  if (prop) return prop;
140  // next scan lua based functions
141  if (out) {
142  LUA_FUNCTION fn;
143  if (UI_GetNodeMethod(node, name, fn)) {
145  out->string = Mem_StrDup(name);
146  out->ofs = fn;
147  out->size = 0;
148  }
149  }
150  // nothing found, report it
151  return nullptr;
152 }
153 
161 {
162  if (behaviour->isInitialized)
163  return;
164 
165  /* everything inherits 'abstractnode' */
166  if (behaviour->extends == nullptr && !Q_streq(behaviour->name, "abstractnode")) {
167  behaviour->extends = "abstractnode";
168  }
169 
170  if (!behaviour->manager && Q_strvalid(behaviour->name)) {
171  Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: Behaviour '%s' expect a manager class", behaviour->name);
172  }
173 
174  if (behaviour->extends) {
176  behaviour->super = UI_GetNodeBehaviour(behaviour->extends);
177  UI_InitializeNodeBehaviour(behaviour->super);
178 
179  /* cache super function if we don't overwrite it */
180  if (behaviour->extraDataSize == 0)
181  behaviour->extraDataSize = behaviour->super->extraDataSize;
182  }
183 
184  /* sort properties by alphabet */
185  if (behaviour->localProperties) {
186  const value_t** oldmemory = behaviour->localProperties;
187  behaviour->localProperties = (const value_t**) UI_AllocHunkMemory(sizeof(value_t*) * (behaviour->propertyCount+1), STRUCT_MEMORY_ALIGN, false);
188  if (behaviour->localProperties == nullptr) {
189  Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: UI memory hunk exceeded - increase the size");
190  }
191 
192  const value_t* previous = nullptr;
193  for (int i = 0; i < behaviour->propertyCount; i++) {
194  const value_t* better = nullptr;
195  /* search the next element after previous */
196  for (const value_t** current = oldmemory; *current != nullptr; current++) {
197  if (previous != nullptr && Q_strcasecmp(previous->string, (*current)->string) >= 0) {
198  continue;
199  }
200  if (better == nullptr || Q_strcasecmp(better->string, (*current)->string) >= 0) {
201  better = *current;
202  }
203  }
204  previous = better;
205  behaviour->localProperties[i] = better;
206  }
207  behaviour->localProperties[behaviour->propertyCount] = nullptr;
208  Mem_Free(oldmemory);
209  }
210 
211  /* property must not overwrite another property */
212  if (behaviour->super && behaviour->localProperties) {
213  const value_t** property = behaviour->localProperties;
214  while (*property) {
215  const value_t* p = UI_GetPropertyFromBehaviour(behaviour->super, (*property)->string);
216 #if 0
217  const uiBehaviour_t* b = UI_GetNodeBehaviour(current->string);
218 #endif
219  if (p != nullptr)
220  Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' overwrite another property", (*property)->string, behaviour->name);
221 #if 0
222  if (b != nullptr)
223  Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' use the name of an existing node behaviour", (*property)->string, behaviour->name);
224 #endif
225  property++;
226  }
227  }
228 
229  /* Sanity: A property must not be outside the node memory */
230  if (behaviour->localProperties) {
231  const int size = sizeof(uiNode_t) + behaviour->extraDataSize;
232  const value_t** property = behaviour->localProperties;
233  while (*property) {
234  if ((*property)->type != V_UI_NODEMETHOD && (*property)->ofs + (*property)->size > size)
235  Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' is outside the node memory. The C code need a fix.", (*property)->string, behaviour->name);
236  property++;
237  }
238  }
239 
240  behaviour->isInitialized = true;
241 }
242 
251 void UI_AddBehaviourMethod (uiBehaviour_t* behaviour, const char* name, LUA_METHOD fcn) {
252  Com_Printf ("UI_AddBehaviourMethod: registering class method [%s] on behaviour [%s]\n", name, behaviour->name);
253 
254  /* the first method, so create a method table on this node */
255  if (!behaviour->nodeMethods) {
256  behaviour->nodeMethods = HASH_NewTable(true, true, false);
257  }
258  /* add the method */
259  if (!HASH_Insert(behaviour->nodeMethods, name, strlen(name), &fcn, sizeof(fcn))) {
260  Com_Printf("UI_AddBehaviourMethod: method [%s] already defined on this behaviour [%s]\n", name, behaviour->name);
261  }
262 }
263 
272 bool UI_GetBehaviourMethod (const uiBehaviour_t* behaviour, const char* name, LUA_METHOD &fcn) {
273  fcn = LUA_NOREF;
274  for(;behaviour;behaviour = behaviour->super) {
275  if (behaviour->nodeMethods) {
276  void* val=HASH_Get(behaviour->nodeMethods, name, strlen(name));
277  if (val != nullptr) {
278  fcn = *((LUA_METHOD *)val);
279  return true;
280  }
281  }
282  }
283  return false;
284 }
285 
292 bool UI_HasBehaviourMethod (uiBehaviour_t* behaviour, const char* name) {
293  LUA_METHOD fn;
294  return UI_GetBehaviourMethod(behaviour, name, fn);
295 }
296 
bool UI_HasBehaviourMethod(uiBehaviour_t *behaviour, const char *name)
Returns true if a node method of given name is available on this behaviour or its super...
const struct value_s * UI_RegisterNodePropertyPosSize_(uiBehaviour_t *behaviour, const char *name, int type, size_t pos, size_t size)
Register a property to a behaviour. It should not be used in the code.
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
void UI_InitializeNodeBehaviour(uiBehaviour_t *behaviour)
Initialize a node behaviour memory, after registration, and before using it.
valueTypes_t
possible values for parsing functions
Definition: scripts.h:48
const char * name
Definition: ui_behaviour.h:41
hashTable_s * nodeMethods
Definition: ui_behaviour.h:58
bool UI_GetBehaviourMethod(const uiBehaviour_t *behaviour, const char *name, LUA_METHOD &fcn)
Finds the lua based method on this behaviour or its super.
#define V_UI_NODEMETHOD
Definition: ui_parse.h:61
uiBehaviour_t * behaviour
Definition: ui_nodes.h:83
UINodePtr manager
Definition: ui_behaviour.h:43
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
valueTypes_t type
Definition: scripts.h:170
#define Mem_StrDup(in)
Definition: mem.h:48
hashTable_s * HASH_NewTable(bool ownsKeys, bool ownsValues, bool duplicateOverwrite)
Creates a new hash table and sets it initial capacity.
Definition: hashtable.cpp:287
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
#define Q_strvalid(string)
Definition: shared.h:141
Internal data use by the UI package.
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
GLsizei size
Definition: r_gl.h:152
#define STRUCT_MEMORY_ALIGN
Definition: ui_internal.h:104
bool isInitialized
Definition: ui_behaviour.h:48
void * HASH_Get(hashTable_s *t, const void *key, int nkey)
Returns the value for a given key.
Definition: hashtable.cpp:467
#define Q_strcasecmp(a, b)
Definition: shared.h:131
int LUA_METHOD
holds a reference to a lua event handler
Definition: scripts_lua.h:53
Atomic structure used to define most of the UI.
Definition: ui_nodes.h:80
const char * string
Definition: scripts.h:169
size_t ofs
Definition: scripts.h:171
#define Mem_PoolAllocTypeN(type, n, pool)
Definition: mem.h:42
#define V_CVAR_OR_LONGSTRING
Definition: ui_parse.h:70
uiBehaviour_t * super
Definition: ui_behaviour.h:55
#define V_UI_NODEMETHOD_LUA
Definition: ui_parse.h:62
intptr_t extraDataSize
Definition: ui_behaviour.h:54
QGL_EXTERN GLint i
Definition: r_gl.h:113
node behaviour, how a node work
Definition: ui_behaviour.h:39
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
const char * extends
Definition: ui_behaviour.h:42
#define Mem_Free(ptr)
Definition: mem.h:35
void UI_AddBehaviourMethod(uiBehaviour_t *behaviour, const char *name, LUA_METHOD fcn)
Adds a lua based method to the list of available behaviour methods for calling.
const value_t ** localProperties
Definition: ui_behaviour.h:52
bool UI_GetNodeMethod(const uiNode_t *node, const char *name, LUA_METHOD &fcn)
Finds the lua based method on this node or its super.
Definition: ui_node.cpp:1104
size_t size
Definition: scripts.h:172
int LUA_FUNCTION
callback signatures for functions defined in Lua
Definition: scripts_lua.h:45
memPool_t * ui_sysPool
Definition: ui_main.cpp:42
#define V_CVAR_OR_STRING
Definition: ui_parse.h:69
#define Q_streq(a, b)
Definition: shared.h:136
void(* uiNodeMethod_t)(uiNode_t *node, const struct uiCallContext_s *context)
Signature of a function to bind a node method.
Definition: ui_behaviour.h:67
const value_t * UI_GetPropertyOrLuaMethod(const uiNode_t *node, const char *name, value_t *out)
Get a property or lua based method from a node, node behaviour or inherted behaviour.
bool HASH_Insert(hashTable_s *t, const void *key, int nkey, const void *value, int nvalue)
Inserts a new value with given key into the hash table.
Definition: hashtable.cpp:369
const struct value_s * UI_RegisterNodeMethod(uiBehaviour_t *behaviour, const char *name, uiNodeMethod_t function)
Register a node method to a behaviour.
#define LOCAL_PROPERTY_SIZE