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