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