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