svn merge ^/trunk/blender -r46340:46350
[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
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stddef.h>
36 #include <string.h>
37 #include <ctype.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "DNA_property_types.h"
42 #include "DNA_object_types.h"
43
44 #include "BLI_blenlib.h"
45
46 #include "BKE_property.h"
47
48 void free_property(bProperty *prop)
49 {
50         
51         if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
52         MEM_freeN(prop);
53         
54 }
55
56 void free_properties(ListBase *lb)
57 {
58         bProperty *prop;
59         
60         while ( (prop = lb->first) ) {
61                 BLI_remlink(lb, prop);
62                 free_property(prop);
63         }
64 }
65
66 bProperty *copy_property(bProperty *prop)
67 {
68         bProperty *propn;
69         
70         propn = MEM_dupallocN(prop);
71         if (prop->poin && prop->poin != &prop->data) {
72                 propn->poin = MEM_dupallocN(prop->poin);
73         }
74         else propn->poin = &propn->data;
75         
76         return propn;
77 }
78
79 void copy_properties(ListBase *lbn, ListBase *lbo)
80 {
81         bProperty *prop, *propn;
82         free_properties(lbn); /* in case we are copying to an object with props */
83         prop = lbo->first;
84         while (prop) {
85                 propn = copy_property(prop);
86                 BLI_addtail(lbn, propn);
87                 prop = prop->next;
88         }
89         
90         
91 }
92
93 void init_property(bProperty *prop)
94 {
95         /* also use when property changes type */
96         
97         if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
98         prop->poin = NULL;
99         
100         prop->data = 0;
101         
102         switch (prop->type) {
103                 case GPROP_BOOL:
104                 case GPROP_INT:
105                 case GPROP_FLOAT:
106                 case GPROP_TIME:
107                         prop->poin = &prop->data;
108                         break;
109                 case GPROP_STRING:
110                         prop->poin = MEM_callocN(MAX_PROPSTRING, "property string");
111                         break;
112         }
113 }
114
115
116 bProperty *new_property(int type)
117 {
118         bProperty *prop;
119
120         prop = MEM_callocN(sizeof(bProperty), "property");
121         prop->type = type;
122
123         init_property(prop);
124         
125         strcpy(prop->name, "prop");
126
127         return prop;
128 }
129
130 /* used by unique_property() only */
131 static bProperty *get_property__internal(bProperty *first, bProperty *self, const char *name)
132 {
133         bProperty *p;
134         for (p = first; p; p = p->next) {
135                 if (p != self && (strcmp(p->name, name) == 0))
136                         return p;
137         }
138         return NULL;
139 }
140 void unique_property(bProperty *first, bProperty *prop, int force)
141 {
142         bProperty *p;
143
144         /* set the first if its not set */
145         if (first == NULL) {
146                 first = prop;
147                 while (first->prev) {
148                         first = first->prev;
149                 }
150         }
151
152         if (force) {
153                 /* change other names to make them unique */
154                 while ((p = get_property__internal(first, prop, prop->name))) {
155                         unique_property(first, p, 0);
156                 }
157         }
158         else {
159                 /* change our own name until its unique */
160                 if (get_property__internal(first, prop, prop->name)) {
161                         /* there is a collision */
162                         char new_name[sizeof(prop->name)];
163                         char base_name[sizeof(prop->name)];
164                         char num[sizeof(prop->name)];
165                         int i = 0;
166
167                         /* strip numbers */
168                         BLI_strncpy(base_name, prop->name, sizeof(base_name));
169                         for (i = strlen(base_name) - 1; (i >= 0 && isdigit(base_name[i])); i--) {
170                                 base_name[i] = '\0';
171                         }
172                         i = 0;
173
174                         do { /* ensure we have enough chars for the new number in the name */
175                                 BLI_snprintf(num, sizeof(num), "%d", i++);
176                                 BLI_strncpy(new_name, base_name, sizeof(prop->name) - strlen(num));
177                                 strcat(new_name, num);
178                         } while (get_property__internal(first, prop, new_name));
179
180                         BLI_strncpy(prop->name, new_name, sizeof(prop->name));
181                 }
182         }
183 }
184
185 bProperty *get_ob_property(Object *ob, const char *name)
186 {
187         return BLI_findstring(&ob->prop, name, offsetof(bProperty, name));
188 }
189
190 void set_ob_property(Object *ob, bProperty *propc)
191 {
192         bProperty *prop;
193         prop = get_ob_property(ob, propc->name);
194         if (prop) {
195                 free_property(prop);
196                 BLI_remlink(&ob->prop, prop);
197         }
198         BLI_addtail(&ob->prop, copy_property(propc));
199 }
200
201 /* negative: prop is smaller
202  * positive: prop is larger
203  */
204 int compare_property(bProperty *prop, const char *str)
205 {
206 //      extern int Gdfra;               /* sector.c */
207         float fvalue, ftest;
208         
209         switch (prop->type) {
210                 case GPROP_BOOL:
211                         if (BLI_strcasecmp(str, "true") == 0) {
212                                 if (prop->data == 1) return 0;
213                                 else return 1;
214                         }
215                         else if (BLI_strcasecmp(str, "false") == 0) {
216                                 if (prop->data == 0) return 0;
217                                 else return 1;
218                         }
219                 /* no break, do GPROP_int too! */
220                 
221                 case GPROP_INT:
222                         return prop->data - atoi(str);
223
224                 case GPROP_FLOAT:
225                 case GPROP_TIME:
226                         // WARNING: untested for GPROP_TIME
227                         // function isn't used currently
228                         fvalue = *((float *)&prop->data);
229                         ftest = (float)atof(str);
230                         if (fvalue > ftest) return 1;
231                         else if (fvalue < ftest) return -1;
232                         return 0;
233
234                 case GPROP_STRING:
235                         return strcmp(prop->poin, str);
236         }
237         
238         return 0;
239 }
240
241 void set_property(bProperty *prop, const char *str)
242 {
243 //      extern int Gdfra;               /* sector.c */
244
245         switch (prop->type) {
246                 case GPROP_BOOL:
247                         if (BLI_strcasecmp(str, "true") == 0) prop->data = 1;
248                         else if (BLI_strcasecmp(str, "false") == 0) prop->data = 0;
249                         else prop->data = (atoi(str) != 0);
250                         break;
251                 case GPROP_INT:
252                         prop->data = atoi(str);
253                         break;
254                 case GPROP_FLOAT:
255                 case GPROP_TIME:
256                         *((float *)&prop->data) = (float)atof(str);
257                         break;
258                 case GPROP_STRING:
259                         strcpy(prop->poin, str); /* TODO - check size? */
260                         break;
261         }
262         
263 }
264
265 void add_property(bProperty *prop, const char *str)
266 {
267 //      extern int Gdfra;               /* sector.c */
268
269         switch (prop->type) {
270                 case GPROP_BOOL:
271                 case GPROP_INT:
272                         prop->data += atoi(str);
273                         break;
274                 case GPROP_FLOAT:
275                 case GPROP_TIME:
276                         *((float *)&prop->data) += (float)atof(str);
277                         break;
278                 case GPROP_STRING:
279                         /* strcpy(prop->poin, str); */
280                         break;
281         }
282 }
283
284 /* reads value of property, sets it in chars in str */
285 void set_property_valstr(bProperty *prop, char *str)
286 {
287 //      extern int Gdfra;               /* sector.c */
288
289         if (str == NULL) return;
290
291         switch (prop->type) {
292                 case GPROP_BOOL:
293                 case GPROP_INT:
294                         sprintf(str, "%d", prop->data);
295                         break;
296                 case GPROP_FLOAT:
297                 case GPROP_TIME:
298                         sprintf(str, "%f", *((float *)&prop->data));
299                         break;
300                 case GPROP_STRING:
301                         BLI_strncpy(str, prop->poin, MAX_PROPSTRING);
302                         break;
303         }
304 }
305
306 void cp_property(bProperty *prop1, bProperty *prop2)
307 {
308         char str[128];
309
310         set_property_valstr(prop2, str);
311
312         set_property(prop1, str);
313 }