c4658712ecb09529ba1ca80322d8b79504dae6ad
[blender.git] / source / blender / blenkernel / intern / property.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): ton roosendaal
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/blenkernel/intern/property.c
29  *  \ingroup bke
30  *
31  * This module deals with bProperty only,
32  * they are used on blender objects in the game engine
33  * (where they get converted into C++ classes - CValue and subclasses)
34  */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stddef.h>
39 #include <string.h>
40 #include <ctype.h>
41
42 #include "MEM_guardedalloc.h"
43
44 #include "DNA_property_types.h"
45 #include "DNA_object_types.h"
46
47 #include "BLI_blenlib.h"
48
49 #include "BKE_property.h"
50
51 void BKE_bproperty_free(bProperty *prop)
52 {
53         
54         if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
55         MEM_freeN(prop);
56         
57 }
58
59 void BKE_bproperty_free_list(ListBase *lb)
60 {
61         bProperty *prop;
62         
63         while ( (prop = lb->first) ) {
64                 BLI_remlink(lb, prop);
65                 BKE_bproperty_free(prop);
66         }
67 }
68
69 bProperty *BKE_bproperty_copy(bProperty *prop)
70 {
71         bProperty *propn;
72         
73         propn = MEM_dupallocN(prop);
74         if (prop->poin && prop->poin != &prop->data) {
75                 propn->poin = MEM_dupallocN(prop->poin);
76         }
77         else propn->poin = &propn->data;
78         
79         return propn;
80 }
81
82 void BKE_bproperty_copy_list(ListBase *lbn, ListBase *lbo)
83 {
84         bProperty *prop, *propn;
85         BKE_bproperty_free_list(lbn); /* in case we are copying to an object with props */
86         prop = lbo->first;
87         while (prop) {
88                 propn = BKE_bproperty_copy(prop);
89                 BLI_addtail(lbn, propn);
90                 prop = prop->next;
91         }
92         
93         
94 }
95
96 void BKE_bproperty_init(bProperty *prop)
97 {
98         /* also use when property changes type */
99         
100         if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
101         prop->poin = NULL;
102         
103         prop->data = 0;
104         
105         switch (prop->type) {
106                 case GPROP_BOOL:
107                 case GPROP_INT:
108                 case GPROP_FLOAT:
109                 case GPROP_TIME:
110                         prop->poin = &prop->data;
111                         break;
112                 case GPROP_STRING:
113                         prop->poin = MEM_callocN(MAX_PROPSTRING, "property string");
114                         break;
115         }
116 }
117
118
119 bProperty *BKE_bproperty_new(int type)
120 {
121         bProperty *prop;
122
123         prop = MEM_callocN(sizeof(bProperty), "property");
124         prop->type = type;
125
126         BKE_bproperty_init(prop);
127         
128         strcpy(prop->name, "prop");
129
130         return prop;
131 }
132
133 /* used by BKE_bproperty_unique() only */
134 static bProperty *bproperty_get(bProperty *first, bProperty *self, const char *name)
135 {
136         bProperty *p;
137         for (p = first; p; p = p->next) {
138                 if (p != self && (strcmp(p->name, name) == 0))
139                         return p;
140         }
141         return NULL;
142 }
143 void BKE_bproperty_unique(bProperty *first, bProperty *prop, int force)
144 {
145         bProperty *p;
146
147         /* set the first if its not set */
148         if (first == NULL) {
149                 first = prop;
150                 while (first->prev) {
151                         first = first->prev;
152                 }
153         }
154
155         if (force) {
156                 /* change other names to make them unique */
157                 while ((p = bproperty_get(first, prop, prop->name))) {
158                         BKE_bproperty_unique(first, p, 0);
159                 }
160         }
161         else {
162                 /* change our own name until its unique */
163                 if (bproperty_get(first, prop, prop->name)) {
164                         /* there is a collision */
165                         char new_name[sizeof(prop->name)];
166                         char base_name[sizeof(prop->name)];
167                         char num[sizeof(prop->name)];
168                         int i = 0;
169
170                         /* strip numbers */
171                         BLI_strncpy(base_name, prop->name, sizeof(base_name));
172                         for (i = strlen(base_name) - 1; (i >= 0 && isdigit(base_name[i])); i--) {
173                                 base_name[i] = '\0';
174                         }
175                         i = 0;
176
177                         do { /* ensure we have enough chars for the new number in the name */
178                                 BLI_snprintf(num, sizeof(num), "%d", i++);
179                                 BLI_strncpy(new_name, base_name, sizeof(prop->name) - strlen(num));
180                                 strcat(new_name, num);
181                         } while (bproperty_get(first, prop, new_name));
182
183                         BLI_strncpy(prop->name, new_name, sizeof(prop->name));
184                 }
185         }
186 }
187
188 bProperty *BKE_bproperty_object_get(Object *ob, const char *name)
189 {
190         return BLI_findstring(&ob->prop, name, offsetof(bProperty, name));
191 }
192
193 void BKE_bproperty_object_set(Object *ob, bProperty *propc)
194 {
195         bProperty *prop;
196         prop = BKE_bproperty_object_get(ob, propc->name);
197         if (prop) {
198                 BKE_bproperty_free(prop);
199                 BLI_remlink(&ob->prop, prop);
200         }
201         BLI_addtail(&ob->prop, BKE_bproperty_copy(propc));
202 }
203
204 /* negative: prop is smaller
205  * positive: prop is larger
206  */
207 #if 0  /* UNUSED */
208 int BKE_bproperty_cmp(bProperty *prop, const char *str)
209 {
210 //      extern int Gdfra;               /* sector.c */
211         float fvalue, ftest;
212         
213         switch (prop->type) {
214                 case GPROP_BOOL:
215                         if (BLI_strcasecmp(str, "true") == 0) {
216                                 if (prop->data == 1) return 0;
217                                 else return 1;
218                         }
219                         else if (BLI_strcasecmp(str, "false") == 0) {
220                                 if (prop->data == 0) return 0;
221                                 else return 1;
222                         }
223                 /* no break, do GPROP_int too! */
224                 
225                 case GPROP_INT:
226                         return prop->data - atoi(str);
227
228                 case GPROP_FLOAT:
229                 case GPROP_TIME:
230                         /* WARNING: untested for GPROP_TIME
231                          * function isn't used currently */
232                         fvalue = *((float *)&prop->data);
233                         ftest = (float)atof(str);
234                         if (fvalue > ftest) return 1;
235                         else if (fvalue < ftest) return -1;
236                         return 0;
237
238                 case GPROP_STRING:
239                         return strcmp(prop->poin, str);
240         }
241         
242         return 0;
243 }
244 #endif
245
246 void BKE_bproperty_set(bProperty *prop, const char *str)
247 {
248 //      extern int Gdfra;               /* sector.c */
249
250         switch (prop->type) {
251                 case GPROP_BOOL:
252                         if (BLI_strcasecmp(str, "true") == 0) prop->data = 1;
253                         else if (BLI_strcasecmp(str, "false") == 0) prop->data = 0;
254                         else prop->data = (atoi(str) != 0);
255                         break;
256                 case GPROP_INT:
257                         prop->data = atoi(str);
258                         break;
259                 case GPROP_FLOAT:
260                 case GPROP_TIME:
261                         *((float *)&prop->data) = (float)atof(str);
262                         break;
263                 case GPROP_STRING:
264                         strcpy(prop->poin, str); /* TODO - check size? */
265                         break;
266         }
267         
268 }
269
270 void BKE_bproperty_add(bProperty *prop, const char *str)
271 {
272 //      extern int Gdfra;               /* sector.c */
273
274         switch (prop->type) {
275                 case GPROP_BOOL:
276                 case GPROP_INT:
277                         prop->data += atoi(str);
278                         break;
279                 case GPROP_FLOAT:
280                 case GPROP_TIME:
281                         *((float *)&prop->data) += (float)atof(str);
282                         break;
283                 case GPROP_STRING:
284                         /* strcpy(prop->poin, str); */
285                         break;
286         }
287 }
288
289 /* reads value of property, sets it in chars in str */
290 void BKE_bproperty_set_valstr(bProperty *prop, char str[MAX_PROPSTRING])
291 {
292 //      extern int Gdfra;               /* sector.c */
293
294         if (str == NULL) return;
295
296         switch (prop->type) {
297                 case GPROP_BOOL:
298                 case GPROP_INT:
299                         sprintf(str, "%d", prop->data);
300                         break;
301                 case GPROP_FLOAT:
302                 case GPROP_TIME:
303                         sprintf(str, "%f", *((float *)&prop->data));
304                         break;
305                 case GPROP_STRING:
306                         BLI_strncpy(str, prop->poin, MAX_PROPSTRING);
307                         break;
308         }
309 }
310
311 #if 0   /* UNUSED */
312 void cp_property(bProperty *prop1, bProperty *prop2)
313 {
314         char str[128];
315
316         BKE_bproperty_set_valstr(prop2, str);
317
318         BKE_bproperty_set(prop1, str);
319 }
320 #endif