fix for incorrect array use when freeing fcurve modifier envelope points, array also...
[blender.git] / source / blender / editors / animation / fmodifier_ui.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) 2009 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation, Joshua Leung
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /** \file blender/editors/animation/fmodifier_ui.c
30  *  \ingroup edanimation
31  */
32
33
34 /* User-Interface Stuff for F-Modifiers:
35  * This file defines the (C-Coded) templates + editing callbacks needed 
36  * by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor,
37  * and NLA-Strips in the NLA Editor.
38  *
39  * Copy/Paste Buffer for F-Modifiers:
40  * For now, this is also defined in this file so that it can be shared between the 
41  */
42  
43 #include <string.h>
44
45 #include "DNA_anim_types.h"
46 #include "DNA_scene_types.h"
47
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_utildefines.h"
52
53 #include "BKE_context.h"
54 #include "BKE_fcurve.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "RNA_access.h"
60
61 #include "UI_interface.h"
62 #include "UI_resources.h"
63
64 #include "ED_anim_api.h"
65
66 /* ********************************************** */
67 /* UI STUFF */
68
69 // XXX! --------------------------------
70 /* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */
71 #define UI_FLT_MAX      10000.0f
72
73 #define B_REDR                                  1
74 #define B_FMODIFIER_REDRAW              20
75
76 /* macro for use here to draw background box and set height */
77 // XXX for now, roundbox has it's callback func set to NULL to not intercept events
78 #define DRAW_BACKDROP(height) \
79         { \
80                 uiDefBut(block, ROUNDBOX, B_REDR, "", -3, yco-height, width+3, height-1, NULL, 5.0, 0.0, 12.0, (float)rb_col, ""); \
81         }
82
83 /* callback to verify modifier data */
84 static void validate_fmodifier_cb (bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg))
85 {
86         FModifier *fcm= (FModifier *)fcm_v;
87         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
88         
89         /* call the verify callback on the modifier if applicable */
90         if (fmi && fmi->verify_data)
91                 fmi->verify_data(fcm);
92 }
93
94 /* callback to remove the given modifier  */
95 static void delete_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v)
96 {
97         ListBase *modifiers = (ListBase *)fmods_v;
98         FModifier *fcm= (FModifier *)fcm_v;
99         
100         /* remove the given F-Modifier from the active modifier-stack */
101         remove_fmodifier(modifiers, fcm);
102         
103         /* send notifiers */
104         // XXX for now, this is the only way to get updates in all the right places... but would be nice to have a special one in this case 
105         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
106 }
107
108 /* --------------- */
109         
110 /* draw settings for generator modifier */
111 static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, short width)
112 {
113         FMod_Generator *data= (FMod_Generator *)fcm->data;
114         uiLayout *col, *row;
115         uiBlock *block;
116         uiBut *but;
117         PointerRNA ptr;
118         
119         /* init the RNA-pointer */
120         RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
121         
122         /* basic settings (backdrop + mode selector + some padding) */
123         col= uiLayoutColumn(layout, 1);
124         block= uiLayoutGetBlock(layout);
125         uiBlockBeginAlign(block);
126                 but= uiDefButR(block, MENU, B_FMODIFIER_REDRAW, NULL, 0, 0, width-30, UI_UNIT_Y, &ptr, "mode", -1, 0, 0, -1, -1, NULL);
127                 uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
128                 
129                 uiDefButR(block, TOG, B_FMODIFIER_REDRAW, NULL, 0, 0, width-30, UI_UNIT_Y, &ptr, "use_additive", -1, 0, 0, -1, -1, NULL);
130         uiBlockEndAlign(block);
131         
132         /* now add settings for individual modes */
133         switch (data->mode) {
134                 case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
135                 {
136                         float *cp = NULL;
137                         char xval[32];
138                         unsigned int i;
139                         
140                         /* draw polynomial order selector */
141                         row= uiLayoutRow(layout, 0);
142                         block= uiLayoutGetBlock(row);
143                                 but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 10,0,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
144                                 uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
145                         
146                         
147                         /* draw controls for each coefficient and a + sign at end of row */
148                         row= uiLayoutRow(layout, 1);
149                         block= uiLayoutGetBlock(row);
150                                 uiDefBut(block, LABEL, 1, "y = ", 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
151                         
152                         cp= data->coefficients;
153                         for (i=0; (i < data->arraysize) && (cp); i++, cp++) {
154                                 /* coefficient */
155                                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 150, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient for polynomial");
156                                 
157                                 /* 'x' param (and '+' if necessary) */
158                                 if (i) {
159                                         if (i == 1)
160                                                 strcpy(xval, "x");
161                                         else
162                                                 sprintf(xval, "x^%d", i);
163                                         uiDefBut(block, LABEL, 1, xval, 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "Power of x");
164                                 }
165                                 
166                                 if ( (i != (data->arraysize - 1)) || ((i==0) && data->arraysize==2) ) {
167                                         uiDefBut(block, LABEL, 1, "+", 0,0 , 30, 20, NULL, 0.0, 0.0, 0, 0, "");
168                                         
169                                         /* next coefficient on a new row */
170                                         row= uiLayoutRow(layout, 1);
171                                         block= uiLayoutGetBlock(row);
172                                 }
173                         }
174                 }
175                         break;
176                 
177                 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial expression */
178                 {
179                         float *cp = NULL;
180                         unsigned int i;
181                         
182                         /* draw polynomial order selector */
183                         row= uiLayoutRow(layout, 0);
184                         block= uiLayoutGetBlock(row);
185                                 but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 0,0,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
186                                 uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
187                         
188                         
189                         /* draw controls for each pair of coefficients */
190                         row= uiLayoutRow(layout, 1);
191                         block= uiLayoutGetBlock(row);
192                                 uiDefBut(block, LABEL, 1, "y=", 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
193                         
194                         cp= data->coefficients;
195                         for (i=0; (i < data->poly_order) && (cp); i++, cp+=2) {
196                                 /* opening bracket */
197                                 uiDefBut(block, LABEL, 1, "(", 0, 0, 20, 20, NULL, 0.0, 0.0, 0, 0, "");
198                                 
199                                 /* coefficients */
200                                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 100, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient of x");
201                                 
202                                 uiDefBut(block, LABEL, 1, "x+", 0, 0, 40, 20, NULL, 0.0, 0.0, 0, 0, "");
203                                 
204                                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 100, 20, cp+1, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Second coefficient");
205                                 
206                                 /* closing bracket and '+' sign */
207                                 if ( (i != (data->poly_order - 1)) || ((i==0) && data->poly_order==2) ) {
208                                         uiDefBut(block, LABEL, 1, ") +", 0, 0, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
209                                         
210                                         /* set up new row for the next pair of coefficients*/
211                                         row= uiLayoutRow(layout, 1);
212                                         block= uiLayoutGetBlock(row);
213                                 }
214                                 else 
215                                         uiDefBut(block, LABEL, 1, ")", 0, 0, 20, 20, NULL, 0.0, 0.0, 0, 0, "");
216                         }
217                 }
218                         break;
219         }
220 }
221
222 /* --------------- */
223
224 /* draw settings for generator modifier */
225 static void draw_modifier__fn_generator(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
226 {
227         uiLayout *col;
228         PointerRNA ptr;
229         
230         /* init the RNA-pointer */
231         RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
232         
233         /* add the settings */
234         col= uiLayoutColumn(layout, 1);
235                 uiItemR(col, &ptr, "function_type", 0, "", ICON_NONE);
236                 uiItemR(col, &ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
237         
238         col= uiLayoutColumn(layout, 0); // no grouping for now
239                 uiItemR(col, &ptr, "amplitude", 0, NULL, ICON_NONE);
240                 uiItemR(col, &ptr, "phase_multiplier", 0, NULL, ICON_NONE);
241                 uiItemR(col, &ptr, "phase_offset", 0, NULL, ICON_NONE);
242                 uiItemR(col, &ptr, "value_offset", 0, NULL, ICON_NONE);
243 }
244
245 /* --------------- */
246
247 /* draw settings for cycles modifier */
248 static void draw_modifier__cycles(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
249 {
250         uiLayout *split, *col;
251         PointerRNA ptr;
252         
253         /* init the RNA-pointer */
254         RNA_pointer_create(id, &RNA_FModifierCycles, fcm, &ptr);
255         
256         /* split into 2 columns 
257          * NOTE: the mode comboboxes shouldn't get labels, otherwise there isn't enough room
258          */
259         split= uiLayoutSplit(layout, 0.5f, 0);
260         
261         /* before range */
262         col= uiLayoutColumn(split, 1);
263                 uiItemL(col, "Before:", ICON_NONE);
264                 uiItemR(col, &ptr, "mode_before", 0, "", ICON_NONE);
265                 uiItemR(col, &ptr, "cycles_before", 0, NULL, ICON_NONE);
266                 
267         /* after range */
268         col= uiLayoutColumn(split, 1);
269                 uiItemL(col, "After:", ICON_NONE);
270                 uiItemR(col, &ptr, "mode_after", 0, "", ICON_NONE);
271                 uiItemR(col, &ptr, "cycles_after", 0, NULL, ICON_NONE);
272 }
273
274 /* --------------- */
275
276 /* draw settings for noise modifier */
277 static void draw_modifier__noise(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
278 {
279         uiLayout *split, *col;
280         PointerRNA ptr;
281         
282         /* init the RNA-pointer */
283         RNA_pointer_create(id, &RNA_FModifierNoise, fcm, &ptr);
284         
285         /* blending mode */
286         uiItemR(layout, &ptr, "blend_type", 0, NULL, ICON_NONE);
287         
288         /* split into 2 columns */
289         split= uiLayoutSplit(layout, 0.5f, 0);
290         
291         /* col 1 */
292         col= uiLayoutColumn(split, 0);
293                 uiItemR(col, &ptr, "scale", 0, NULL, ICON_NONE);
294                 uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE);
295         
296         /* col 2 */
297         col= uiLayoutColumn(split, 0);
298                 uiItemR(col, &ptr, "phase", 0, NULL, ICON_NONE);
299                 uiItemR(col, &ptr, "depth", 0, NULL, ICON_NONE);
300 }
301
302 /* --------------- */
303
304 #define BINARYSEARCH_FRAMEEQ_THRESH     0.0001
305
306 /* Binary search algorithm for finding where to insert Envelope Data Point.
307  * Returns the index to insert at (data already at that index will be offset if replace is 0)
308  */
309 static int binarysearch_fcm_envelopedata_index (FCM_EnvelopeData array[], float frame, int arraylen, short *exists)
310 {
311         int start=0, end=arraylen;
312         int loopbreaker= 0, maxloop= arraylen * 2;
313         
314         /* initialise exists-flag first */
315         *exists= 0;
316         
317         /* sneaky optimisations (don't go through searching process if...):
318          *      - keyframe to be added is to be added out of current bounds
319          *      - keyframe to be added would replace one of the existing ones on bounds
320          */
321         if ((arraylen <= 0) || (array == NULL)) {
322                 printf("Warning: binarysearch_fcm_envelopedata_index() encountered invalid array \n");
323                 return 0;
324         }
325         else {
326                 /* check whether to add before/after/on */
327                 float framenum;
328                 
329                 /* 'First' Point (when only one point, this case is used) */
330                 framenum= array[0].time;
331                 if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
332                         *exists = 1;
333                         return 0;
334                 }
335                 else if (frame < framenum)
336                         return 0;
337                         
338                 /* 'Last' Point */
339                 framenum= array[(arraylen-1)].time;
340                 if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
341                         *exists= 1;
342                         return (arraylen - 1);
343                 }
344                 else if (frame > framenum)
345                         return arraylen;
346         }
347         
348         
349         /* most of the time, this loop is just to find where to put it
350          *      - 'loopbreaker' is just here to prevent infinite loops 
351          */
352         for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
353                 /* compute and get midpoint */
354                 int mid = start + ((end - start) / 2);  /* we calculate the midpoint this way to avoid int overflows... */
355                 float midfra= array[mid].time;
356                 
357                 /* check if exactly equal to midpoint */
358                 if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) {
359                         *exists = 1;
360                         return mid;
361                 }
362                 
363                 /* repeat in upper/lower half */
364                 if (frame > midfra)
365                         start= mid + 1;
366                 else if (frame < midfra)
367                         end= mid - 1;
368         }
369         
370         /* print error if loop-limit exceeded */
371         if (loopbreaker == (maxloop-1)) {
372                 printf("Error: binarysearch_fcm_envelopedata_index() was taking too long \n");
373                 
374                 // include debug info 
375                 printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
376         }
377         
378         /* not found, so return where to place it */
379         return start;
380 }
381
382 /* callback to add new envelope data point */
383 // TODO: should we have a separate file for things like this?
384 static void fmod_envelope_addpoint_cb (bContext *C, void *fcm_dv, void *UNUSED(arg))
385 {
386         Scene *scene= CTX_data_scene(C);
387         FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
388         FCM_EnvelopeData *fedn;
389         FCM_EnvelopeData fed;
390         
391         /* init template data */
392         fed.min= -1.0f;
393         fed.max= 1.0f;
394         fed.time= (float)scene->r.cfra; // XXX make this int for ease of use?
395         fed.f1= fed.f2= 0;
396         
397         /* check that no data exists for the current frame... */
398         if (env->data) {
399                 short exists = -1;
400                 int i= binarysearch_fcm_envelopedata_index(env->data, (float)(scene->r.cfra), env->totvert, &exists);
401                 
402                 /* binarysearch_...() will set exists by default to 0, so if it is non-zero, that means that the point exists already */
403                 if (exists)
404                         return;
405                         
406                 /* add new */
407                 fedn= MEM_callocN((env->totvert+1)*sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
408                 
409                 /* add the points that should occur before the point to be pasted */
410                 if (i > 0)
411                         memcpy(fedn, env->data, i*sizeof(FCM_EnvelopeData));
412                 
413                 /* add point to paste at index i */
414                 *(fedn + i)= fed;
415                 
416                 /* add the points that occur after the point to be pasted */
417                 if (i < env->totvert) 
418                         memcpy(fedn+i+1, env->data+i, (env->totvert-i)*sizeof(FCM_EnvelopeData));
419                 
420                 /* replace (+ free) old with new */
421                 MEM_freeN(env->data);
422                 env->data= fedn;
423                 
424                 env->totvert++;
425         }
426         else {
427                 env->data= MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
428                 *(env->data)= fed;
429                 
430                 env->totvert= 1;
431         }
432 }
433
434 /* callback to remove envelope data point */
435 // TODO: should we have a separate file for things like this?
436 static void fmod_envelope_deletepoint_cb (bContext *UNUSED(C), void *fcm_dv, void *ind_v)
437 {
438         FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
439         FCM_EnvelopeData *fedn;
440         int index= GET_INT_FROM_POINTER(ind_v);
441         
442         /* check that no data exists for the current frame... */
443         if (env->totvert > 1) {
444                 /* allocate a new smaller array */
445                 fedn= MEM_callocN(sizeof(FCM_EnvelopeData)*(env->totvert-1), "FCM_EnvelopeData");
446
447                 memcpy(fedn, env->data, sizeof(FCM_EnvelopeData)*(index));
448                 memcpy(fedn + index, env->data + (index + 1), sizeof(FCM_EnvelopeData)*((env->totvert - index)-1));
449                 
450                 /* free old array, and set the new */
451                 MEM_freeN(env->data);
452                 env->data= fedn;
453                 env->totvert--;
454         }
455         else {
456                 /* just free array, since the only vert was deleted */
457                 if (env->data) {
458                         MEM_freeN(env->data);
459                         env->data= NULL;
460                 }
461                 env->totvert= 0;
462         }
463 }
464
465 /* draw settings for envelope modifier */
466 static void draw_modifier__envelope(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
467 {
468         FMod_Envelope *env= (FMod_Envelope *)fcm->data;
469         FCM_EnvelopeData *fed;
470         uiLayout *col, *row;
471         uiBlock *block;
472         uiBut *but;
473         PointerRNA ptr;
474         int i;
475         
476         /* init the RNA-pointer */
477         RNA_pointer_create(id, &RNA_FModifierEnvelope, fcm, &ptr);
478         
479         /* general settings */
480         col= uiLayoutColumn(layout, 1);
481                 uiItemL(col, "Envelope:", ICON_NONE);
482                 uiItemR(col, &ptr, "reference_value", 0, NULL, ICON_NONE);
483                 
484                 row= uiLayoutRow(col, 1);
485                         uiItemR(row, &ptr, "default_min", 0, "Min", ICON_NONE);
486                         uiItemR(row, &ptr, "default_max", 0, "Max", ICON_NONE);
487                         
488         /* control points header */
489         // TODO: move this control-point control stuff to using the new special widgets for lists
490         // the current way is far too cramped
491         row= uiLayoutRow(layout, 0);
492         block= uiLayoutGetBlock(row);
493                 
494                 uiDefBut(block, LABEL, 1, "Control Points:", 0, 0, 150, 20, NULL, 0.0, 0.0, 0, 0, "");
495                 
496                 but= uiDefBut(block, BUT, B_FMODIFIER_REDRAW, "Add Point", 0,0,150,19, NULL, 0, 0, 0, 0, "Adds a new control-point to the envelope on the current frame");
497                 uiButSetFunc(but, fmod_envelope_addpoint_cb, env, NULL);
498                 
499         /* control points list */
500         for (i=0, fed=env->data; i < env->totvert; i++, fed++) {
501                 /* get a new row to operate on */
502                 row= uiLayoutRow(layout, 1);
503                 block= uiLayoutGetBlock(row);
504                 
505                 uiBlockBeginAlign(block);
506                         but=uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Fra:", 0, 0, 90, 20, &fed->time, -MAXFRAMEF, MAXFRAMEF, 10, 1, "Frame that envelope point occurs");
507                         uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
508                         
509                         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Min:", 0, 0, 100, 20, &fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Minimum bound of envelope at this point");
510                         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Max:", 0, 0, 100, 20, &fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Maximum bound of envelope at this point");
511                         
512                         but= uiDefIconBut(block, BUT, B_FMODIFIER_REDRAW, ICON_X, 0, 0, 18, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Delete envelope control point");
513                         uiButSetFunc(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i));
514                 uiBlockBeginAlign(block);
515         }
516 }
517
518 /* --------------- */
519
520 /* draw settings for limits modifier */
521 static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
522 {
523         uiLayout *split, *col, *row;
524         PointerRNA ptr;
525         
526         /* init the RNA-pointer */
527         RNA_pointer_create(id, &RNA_FModifierLimits, fcm, &ptr);
528         
529         /* row 1: minimum */
530         {
531                 row= uiLayoutRow(layout, 0);
532                 
533                 /* split into 2 columns */
534                 split= uiLayoutSplit(layout, 0.5f, 0);
535                 
536                 /* x-minimum */
537                 col= uiLayoutColumn(split, 1);
538                         uiItemR(col, &ptr, "use_min_x", 0, NULL, ICON_NONE);
539                         uiItemR(col, &ptr, "min_x", 0, NULL, ICON_NONE);
540                         
541                 /* y-minimum*/
542                 col= uiLayoutColumn(split, 1);
543                         uiItemR(col, &ptr, "use_min_y", 0, NULL, ICON_NONE);
544                         uiItemR(col, &ptr, "min_y", 0, NULL, ICON_NONE);
545         }
546         
547         /* row 2: maximum */
548         {
549                 row= uiLayoutRow(layout, 0);
550                 
551                 /* split into 2 columns */
552                 split= uiLayoutSplit(layout, 0.5f, 0);
553                 
554                 /* x-minimum */
555                 col= uiLayoutColumn(split, 1);
556                         uiItemR(col, &ptr, "use_max_x", 0, NULL, ICON_NONE);
557                         uiItemR(col, &ptr, "max_x", 0, NULL, ICON_NONE);
558                         
559                 /* y-minimum*/
560                 col= uiLayoutColumn(split, 1);
561                         uiItemR(col, &ptr, "use_max_y", 0, NULL, ICON_NONE);
562                         uiItemR(col, &ptr, "max_y", 0, NULL, ICON_NONE);
563         }
564 }
565
566 /* --------------- */
567
568 /* draw settings for stepped interpolation modifier */
569 static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
570 {
571         uiLayout *col, *subcol;
572         PointerRNA ptr;
573         
574         /* init the RNA-pointer */
575         RNA_pointer_create(id, &RNA_FModifierStepped, fcm, &ptr);
576         
577         /* block 1: "stepping" settings */
578         col= uiLayoutColumn(layout, 0);
579                 uiItemR(col, &ptr, "frame_step", 0, NULL, ICON_NONE);
580                 uiItemR(col, &ptr, "frame_offset", 0, NULL, ICON_NONE);
581                 
582         /* block 2: start range settings */
583         col= uiLayoutColumn(layout, 1);
584                 uiItemR(col, &ptr, "use_frame_start", 0, NULL, ICON_NONE);
585                 
586                 subcol = uiLayoutColumn(col, 1);
587                 uiLayoutSetActive(subcol, RNA_boolean_get(&ptr, "use_frame_start"));
588                         uiItemR(subcol, &ptr, "frame_start", 0, NULL, ICON_NONE);
589                         
590         /* block 3: end range settings */
591         col= uiLayoutColumn(layout, 1);
592                 uiItemR(col, &ptr, "use_frame_end", 0, NULL, ICON_NONE);
593                 
594                 subcol = uiLayoutColumn(col, 1);
595                 uiLayoutSetActive(subcol, RNA_boolean_get(&ptr, "use_frame_end"));
596                         uiItemR(subcol, &ptr, "frame_end", 0, NULL, ICON_NONE);
597 }
598
599 /* --------------- */
600
601 void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
602 {
603         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
604         uiLayout *box, *row, *subrow;
605         uiBlock *block;
606         uiBut *but;
607         short width= 314;
608         PointerRNA ptr;
609         
610         /* init the RNA-pointer */
611         RNA_pointer_create(id, &RNA_FModifier, fcm, &ptr);
612         
613         /* draw header */
614         {
615                 /* get layout-row + UI-block for this */
616                 box= uiLayoutBox(layout);
617                 
618                 row= uiLayoutRow(box, 0);
619                 block= uiLayoutGetBlock(row); // err...
620                 
621                 /* left-align -------------------------------------------- */
622                 subrow= uiLayoutRow(row, 0);
623                 uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT);
624                 
625                 uiBlockSetEmboss(block, UI_EMBOSSN);
626                 
627                 /* expand */
628                 uiItemR(subrow, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
629                 
630                 /* checkbox for 'active' status (for now) */
631                 uiItemR(subrow, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
632                 
633                 /* name */
634                 if (fmi)
635                         uiItemL(subrow, fmi->name, ICON_NONE);
636                 else
637                         uiItemL(subrow, "<Unknown Modifier>", ICON_NONE);
638                 
639                 /* right-align ------------------------------------------- */
640                 subrow= uiLayoutRow(row, 0);
641                 uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT);
642                 
643                 
644                 /* 'mute' button */
645                 uiItemR(subrow, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
646                 
647                 uiBlockSetEmboss(block, UI_EMBOSSN);
648                 
649                 /* delete button */
650                 but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Delete F-Curve Modifier.");
651                 uiButSetFunc(but, delete_fmodifier_cb, modifiers, fcm);
652                 
653                 uiBlockSetEmboss(block, UI_EMBOSS);
654         }
655         
656         /* when modifier is expanded, draw settings */
657         if (fcm->flag & FMODIFIER_FLAG_EXPANDED) {
658                 /* set up the flexible-box layout which acts as the backdrop for the modifier settings */
659                 box= uiLayoutBox(layout); 
660                 
661                 /* draw settings for individual modifiers */
662                 switch (fcm->type) {
663                         case FMODIFIER_TYPE_GENERATOR: /* Generator */
664                                 draw_modifier__generator(box, id, fcm, width);
665                                 break;
666                                 
667                         case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */
668                                 draw_modifier__fn_generator(box, id, fcm, width);
669                                 break;
670                                 
671                         case FMODIFIER_TYPE_CYCLES: /* Cycles */
672                                 draw_modifier__cycles(box, id, fcm, width);
673                                 break;
674                                 
675                         case FMODIFIER_TYPE_ENVELOPE: /* Envelope */
676                                 draw_modifier__envelope(box, id, fcm, width);
677                                 break;
678                                 
679                         case FMODIFIER_TYPE_LIMITS: /* Limits */
680                                 draw_modifier__limits(box, id, fcm, width);
681                                 break;
682                         
683                         case FMODIFIER_TYPE_NOISE: /* Noise */
684                                 draw_modifier__noise(box, id, fcm, width);
685                                 break;
686                                 
687                         case FMODIFIER_TYPE_STEPPED: /* Stepped */
688                                 draw_modifier__stepped(box, id, fcm, width);
689                                 break;
690                         
691                         default: /* unknown type */
692                                 break;
693                 }
694         }
695 }
696
697 /* ********************************************** */
698 /* COPY/PASTE BUFFER STUFF */
699
700 /* Copy/Paste Buffer itself (list of FModifier 's) */
701 static ListBase fmodifier_copypaste_buf = {NULL, NULL};
702
703 /* ---------- */
704
705 /* free the copy/paste buffer */
706 void free_fmodifiers_copybuf (void)
707 {
708         /* just free the whole buffer */
709         free_fmodifiers(&fmodifier_copypaste_buf);
710 }
711
712 /* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
713  * assuming that the buffer has been cleared already with free_fmodifiers_copybuf()
714  *      - active: only copy the active modifier
715  */
716 short ANIM_fmodifiers_copy_to_buf (ListBase *modifiers, short active)
717 {
718         short ok = 1;
719         
720         /* sanity checks */
721         if ELEM(NULL, modifiers, modifiers->first)
722                 return 0;
723                 
724         /* copy the whole list, or just the active one? */
725         if (active) {
726                 FModifier *fcm = find_active_fmodifier(modifiers);
727                 
728                 if (fcm) {
729                         FModifier *fcmN = copy_fmodifier(fcm);
730                         BLI_addtail(&fmodifier_copypaste_buf, fcmN);
731                 }
732                 else
733                         ok = 0;
734         }
735         else
736                 copy_fmodifiers(&fmodifier_copypaste_buf, modifiers);
737                 
738         /* did we succeed? */
739         return ok;
740 }
741
742 /* 'Paste' the F-Modifier(s) from the buffer to the specified list 
743  *      - replace: free all the existing modifiers to leave only the pasted ones 
744  */
745 short ANIM_fmodifiers_paste_from_buf (ListBase *modifiers, short replace)
746 {
747         FModifier *fcm;
748         short ok = 0;
749         
750         /* sanity checks */
751         if (modifiers == NULL)
752                 return 0;
753                 
754         /* if replacing the list, free the existing modifiers */
755         if (replace)
756                 free_fmodifiers(modifiers);
757                 
758         /* now copy over all the modifiers in the buffer to the end of the list */
759         for (fcm= fmodifier_copypaste_buf.first; fcm; fcm= fcm->next) {
760                 /* make a copy of it */
761                 FModifier *fcmN = copy_fmodifier(fcm);
762                 
763                 /* make sure the new one isn't active, otherwise the list may get several actives */
764                 fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE;
765                 
766                 /* now add it to the end of the list */
767                 BLI_addtail(modifiers, fcmN);
768                 ok = 1;
769         }
770         
771         /* did we succeed? */
772         return ok;
773 }
774
775 /* ********************************************** */