UFO: Alien Invasion
Loading...
Searching...
No Matches
ui_behaviour.cpp
Go to the documentation of this file.
1
4
5/*
6Copyright (C) 2002-2025 UFO: Alien Invasion.
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25#include "ui_main.h"
26#include "ui_internal.h"
27#include "ui_behaviour.h"
28#include "ui_parse.h"
29
34
38#define LOCAL_PROPERTY_SIZE 128
39
40
53const 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
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
88const 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
100const 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
136const 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);
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
251void 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
272bool 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
292bool UI_HasBehaviourMethod (uiBehaviour_t* behaviour, const char* name) {
293 LUA_METHOD fn;
294 return UI_GetBehaviourMethod(behaviour, name, fn);
295}
296
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define ERR_FATAL
Definition common.h:210
void * HASH_Get(hashTable_s *t, const void *key, int nkey)
Returns the value for a given key.
hashTable_s * HASH_NewTable(bool ownsKeys, bool ownsValues, bool duplicateOverwrite)
Creates a new hash table and sets it initial capacity.
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.
Header file for hashtable.
voidpf void uLong size
Definition ioapi.h:42
#define Mem_PoolAllocTypeN(type, n, pool)
Definition mem.h:42
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_StrDup(in)
Definition mem.h:48
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
Header for script parsing functions.
valueTypes_t
possible values for parsing functions
Definition scripts.h:48
@ V_LONGSTRING
Definition scripts.h:60
@ V_STRING
Definition scripts.h:58
Header for lua script functions.
int LUA_FUNCTION
callback signatures for functions defined in Lua
Definition scripts_lua.h:45
int LUA_METHOD
holds a reference to a lua event handler
Definition scripts_lua.h:53
#define Q_strvalid(string)
Definition shared.h:141
#define Q_strcasecmp(a, b)
Definition shared.h:131
#define Q_streq(a, b)
Definition shared.h:136
node behaviour, how a node work
const char * name
UINodePtr manager
const char * extends
hashTable_s * nodeMethods
uiBehaviour_t * super
intptr_t extraDataSize
const value_t ** localProperties
Atomic structure used to define most of the UI.
Definition ui_nodes.h:80
uiBehaviour_t * behaviour
Definition ui_nodes.h:83
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
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.
void UI_InitializeNodeBehaviour(uiBehaviour_t *behaviour)
Initialize a node behaviour memory, after registration, and before using it.
#define LOCAL_PROPERTY_SIZE
bool UI_GetBehaviourMethod(const uiBehaviour_t *behaviour, const char *name, LUA_METHOD &fcn)
Finds the lua based method on this behaviour or its super.
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.
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_AddBehaviourMethod(uiBehaviour_t *behaviour, const char *name, LUA_METHOD fcn)
Adds a lua based method to the list of available behaviour methods for calling.
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_RegisterNodeMethod(uiBehaviour_t *behaviour, const char *name, uiNodeMethod_t function)
Register a node method to a behaviour.
void(* uiNodeMethod_t)(uiNode_t *node, const struct uiCallContext_s *context)
Signature of a function to bind a node method.
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
#define STRUCT_MEMORY_ALIGN
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:1116
uiBehaviour_t * UI_GetNodeBehaviour(const char *name)
Return a node behaviour by name.
Definition ui_nodes.cpp:559
#define V_UI_NODEMETHOD
Definition ui_parse.h:61
#define V_CVAR_OR_LONGSTRING
Definition ui_parse.h:70
#define V_UI_NODEMETHOD_LUA
Definition ui_parse.h:62
#define V_CVAR_OR_STRING
Definition ui_parse.h:69