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