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