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