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