5968817a9a660fa8aba65b3cc370c8fc4e0a81b8
[blender-staging.git] / source / blender / editors / animation / fmodifier_ui.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 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_arithb.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 *fcu_v, void *fcm_v)
116 {
117         FCurve *fcu= (FCurve *)fcu_v;
118         FModifier *fcm= (FModifier *)fcm_v;
119         
120         /* call API function to set the active modifier for active F-Curve */
121         fcurve_set_active_modifier(fcu, fcm);
122 }
123
124 /* callback to remove the given modifier  */
125 static void delete_fmodifier_cb (bContext *C, void *fcu_v, void *fcm_v)
126 {
127         FCurve *fcu= (FCurve *)fcu_v;
128         FModifier *fcm= (FModifier *)fcm_v;
129         
130         /* remove the given F-Modifier from the F-Curve */
131         fcurve_remove_modifier(fcu, fcm);
132 }
133
134 /* --------------- */
135         
136 /* draw settings for generator modifier */
137 static void draw_modifier__generator(uiBlock *block, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
138 {
139         FMod_Generator *data= (FMod_Generator *)fcm->data;
140         char gen_mode[]="Generator Type%t|Expanded Polynomial%x0|Factorised Polynomial%x1";
141         int cy= *yco - 30;
142         uiBut *but;
143         
144         /* set the height */
145         (*height) = 90;
146         switch (data->mode) {
147                 case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
148                         (*height) += 20*(data->poly_order+1) + 20;
149                         break;
150                 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
151                         (*height) += 20 * data->poly_order + 15;
152                         break;
153         }
154         
155         /* basic settings (backdrop + mode selector + some padding) */
156         DRAW_BACKDROP((*height));
157         uiBlockBeginAlign(block);
158                 but= uiDefButI(block, MENU, B_FMODIFIER_REDRAW, gen_mode, 10,cy,width-30,19, &data->mode, 0, 0, 0, 0, "Selects type of generator algorithm.");
159                 uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
160                 cy -= 20;
161                 
162                 uiDefButBitI(block, TOG, FCM_GENERATOR_ADDITIVE, B_FMODIFIER_REDRAW, "Additive", 10,cy,width-30,19, &data->flag, 0, 0, 0, 0, "Values generated by this modifier are applied on top of the existing values instead of overwriting them");
163                 cy -= 35;
164         uiBlockEndAlign(block);
165         
166         /* now add settings for individual modes */
167         switch (data->mode) {
168                 case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
169                 {
170                         float *cp = NULL;
171                         char xval[32];
172                         unsigned int i;
173                         
174                         /* draw polynomial order selector */
175                         but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 10,cy,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
176                         uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
177                         cy -= 35;
178                         
179                         /* draw controls for each coefficient and a + sign at end of row */
180                         uiDefBut(block, LABEL, 1, "y = ", 0, cy, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
181                         
182                         cp= data->coefficients;
183                         for (i=0; (i < data->arraysize) && (cp); i++, cp++) {
184                                 /* coefficient */
185                                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 50, cy, 150, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient for polynomial");
186                                 
187                                 /* 'x' param (and '+' if necessary) */
188                                 if (i == 0)
189                                         strcpy(xval, "");
190                                 else if (i == 1)
191                                         strcpy(xval, "x");
192                                 else
193                                         sprintf(xval, "x^%d", i);
194                                 uiDefBut(block, LABEL, 1, xval, 200, cy, 50, 20, NULL, 0.0, 0.0, 0, 0, "Power of x");
195                                 
196                                 if ( (i != (data->arraysize - 1)) || ((i==0) && data->arraysize==2) )
197                                         uiDefBut(block, LABEL, 1, "+", 250, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
198                                 
199                                 cy -= 20;
200                         }
201                 }
202                         break;
203                 
204                 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial expression */
205                 {
206                         float *cp = NULL;
207                         unsigned int i;
208                         
209                         /* draw polynomial order selector */
210                         but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 10,cy,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
211                         uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
212                         cy -= 35;
213                         
214                         /* draw controls for each pair of coefficients */
215                         uiDefBut(block, LABEL, 1, "y = ", 0, cy, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
216                         
217                         cp= data->coefficients;
218                         for (i=0; (i < data->poly_order) && (cp); i++, cp+=2) {
219                                 /* opening bracket */
220                                 uiDefBut(block, LABEL, 1, "(", 40, cy, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
221                                 
222                                 /* coefficients */
223                                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 50, cy, 100, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient of x");
224                                 
225                                 uiDefBut(block, LABEL, 1, "x + ", 150, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
226                                 
227                                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 180, cy, 100, 20, cp+1, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Second coefficient");
228                                 
229                                 /* closing bracket and '+' sign */
230                                 if ( (i != (data->poly_order - 1)) || ((i==0) && data->poly_order==2) )
231                                         uiDefBut(block, LABEL, 1, ") ?", 280, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
232                                 else
233                                         uiDefBut(block, LABEL, 1, ")", 280, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
234                                 
235                                 cy -= 20;
236                         }
237                 }
238                         break;
239         }
240 }
241
242 /* --------------- */
243
244 /* draw settings for noise modifier */
245 static void draw_modifier__fn_generator(uiBlock *block, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
246 {
247         FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data;
248         int cy= (*yco - 30), cy1= (*yco - 50), cy2= (*yco - 70);
249         char fn_type[]="Built-In Function%t|Sin%x0|Cos%x1|Tan%x2|Square Root%x3|Natural Log%x4|Normalised Sin%x5";
250         
251         /* set the height */
252         (*height) = 80;
253         
254         /* basic settings (backdrop + some padding) */
255         DRAW_BACKDROP((*height));
256         
257         uiDefButI(block, MENU, B_FMODIFIER_REDRAW, fn_type,
258                           3, cy, 300, 20, &data->type, 0, 0, 0, 0, "Type of function used to generate values");
259         
260         
261         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Amplitude:", 
262                           3, cy1, 150, 20, &data->amplitude, 0.000001, 10000.0, 0.01, 3, "Scale factor determining the maximum/minimum values.");
263         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Value Offset:", 
264                           3, cy2, 150, 20, &data->value_offset, 0.0, 10000.0, 0.01, 3, "Constant factor to offset values by.");
265         
266         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Phase Multiplier:", 
267                           155, cy1, 150, 20, &data->phase_multiplier, 0.0, 100000.0, 0.1, 3, "Scale factor determining the 'speed' of the function.");
268         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Phase Offset:", 
269                           155, cy2, 150, 20, &data->phase_offset, 0.0, 100000.0, 0.1, 3, "Constant factor to offset time by for function.");
270
271 }
272
273 /* --------------- */
274
275 /* draw settings for cycles modifier */
276 static void draw_modifier__cycles(uiBlock *block, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
277 {
278         FMod_Cycles *data= (FMod_Cycles *)fcm->data;
279         char cyc_mode[]="Cycling Mode%t|No Cycles%x0|Repeat Motion%x1|Repeat with Offset%x2|Repeat Mirrored%x3";
280         int cy= (*yco - 30), cy1= (*yco - 50), cy2= (*yco - 70);
281         
282         /* set the height */
283         (*height) = 80;
284         
285         /* basic settings (backdrop + some padding) */
286         DRAW_BACKDROP((*height));
287         
288         /* 'before' range */
289         uiDefBut(block, LABEL, 1, "Before:", 4, cy, 80, 20, NULL, 0.0, 0.0, 0, 0, "Settings for cycling before first keyframe");
290         uiBlockBeginAlign(block);
291                 uiDefButS(block, MENU, B_FMODIFIER_REDRAW, cyc_mode, 3,cy1,150,20, &data->before_mode, 0, 0, 0, 0, "Cycling mode to use before first keyframe");
292                 uiDefButS(block, NUM, B_FMODIFIER_REDRAW, "Max Cycles:", 3, cy2, 150, 20, &data->before_cycles, 0, 10000, 10, 3, "Maximum number of cycles to allow (0 = infinite)");
293         uiBlockEndAlign(block);
294         
295         /* 'after' range */
296         uiDefBut(block, LABEL, 1, "After:", 155, cy, 80, 20, NULL, 0.0, 0.0, 0, 0, "Settings for cycling after last keyframe");
297         uiBlockBeginAlign(block);
298                 uiDefButS(block, MENU, B_FMODIFIER_REDRAW, cyc_mode, 157,cy1,150,20, &data->after_mode, 0, 0, 0, 0, "Cycling mode to use after first keyframe");
299                 uiDefButS(block, NUM, B_FMODIFIER_REDRAW, "Max Cycles:", 157, cy2, 150, 20, &data->after_cycles, 0, 10000, 10, 3, "Maximum number of cycles to allow (0 = infinite)");
300         uiBlockEndAlign(block);
301 }
302
303 /* --------------- */
304
305 /* draw settings for noise modifier */
306 static void draw_modifier__noise(uiBlock *block, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
307 {
308         FMod_Noise *data= (FMod_Noise *)fcm->data;
309         int cy= (*yco - 30), cy1= (*yco - 50), cy2= (*yco - 70);
310         char blend_mode[]="Modification %t|Replace %x0|Add %x1|Subtract %x2|Multiply %x3";
311         
312         /* set the height */
313         (*height) = 80;
314         
315         /* basic settings (backdrop + some padding) */
316         DRAW_BACKDROP((*height));
317         
318         uiDefButS(block, MENU, B_FMODIFIER_REDRAW, blend_mode,
319                           3, cy, 150, 20, &data->modification, 0, 0, 0, 0, "Method of combining the results of this modifier and other modifiers.");
320         
321         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Size:", 
322                           3, cy1, 150, 20, &data->size, 0.000001, 10000.0, 0.01, 3, "");
323         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Strength:", 
324                           3, cy2, 150, 20, &data->strength, 0.0, 10000.0, 0.01, 3, "");
325         
326         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Phase:", 
327                           155, cy1, 150, 20, &data->phase, 0.0, 100000.0, 0.1, 3, "");
328         uiDefButS(block, NUM, B_FMODIFIER_REDRAW, "Depth:", 
329                           155, cy2, 150, 20, &data->depth, 0, 128, 1, 3, "");
330
331 }
332
333 /* --------------- */
334
335 #define BINARYSEARCH_FRAMEEQ_THRESH     0.0001
336
337 /* Binary search algorithm for finding where to insert Envelope Data Point.
338  * Returns the index to insert at (data already at that index will be offset if replace is 0)
339  */
340 static int binarysearch_fcm_envelopedata_index (FCM_EnvelopeData array[], float frame, int arraylen, short *exists)
341 {
342         int start=0, end=arraylen;
343         int loopbreaker= 0, maxloop= arraylen * 2;
344         
345         /* initialise exists-flag first */
346         *exists= 0;
347         
348         /* sneaky optimisations (don't go through searching process if...):
349          *      - keyframe to be added is to be added out of current bounds
350          *      - keyframe to be added would replace one of the existing ones on bounds
351          */
352         if ((arraylen <= 0) || (array == NULL)) {
353                 printf("Warning: binarysearch_fcm_envelopedata_index() encountered invalid array \n");
354                 return 0;
355         }
356         else {
357                 /* check whether to add before/after/on */
358                 float framenum;
359                 
360                 /* 'First' Point (when only one point, this case is used) */
361                 framenum= array[0].time;
362                 if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
363                         *exists = 1;
364                         return 0;
365                 }
366                 else if (frame < framenum)
367                         return 0;
368                         
369                 /* 'Last' Point */
370                 framenum= array[(arraylen-1)].time;
371                 if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
372                         *exists= 1;
373                         return (arraylen - 1);
374                 }
375                 else if (frame > framenum)
376                         return arraylen;
377         }
378         
379         
380         /* most of the time, this loop is just to find where to put it
381          *      - 'loopbreaker' is just here to prevent infinite loops 
382          */
383         for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
384                 /* compute and get midpoint */
385                 int mid = start + ((end - start) / 2);  /* we calculate the midpoint this way to avoid int overflows... */
386                 float midfra= array[mid].time;
387                 
388                 /* check if exactly equal to midpoint */
389                 if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) {
390                         *exists = 1;
391                         return mid;
392                 }
393                 
394                 /* repeat in upper/lower half */
395                 if (frame > midfra)
396                         start= mid + 1;
397                 else if (frame < midfra)
398                         end= mid - 1;
399         }
400         
401         /* print error if loop-limit exceeded */
402         if (loopbreaker == (maxloop-1)) {
403                 printf("Error: binarysearch_fcm_envelopedata_index() was taking too long \n");
404                 
405                 // include debug info 
406                 printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
407         }
408         
409         /* not found, so return where to place it */
410         return start;
411 }
412
413 /* callback to add new envelope data point */
414 // TODO: should we have a separate file for things like this?
415 static void fmod_envelope_addpoint_cb (bContext *C, void *fcm_dv, void *dummy)
416 {
417         Scene *scene= CTX_data_scene(C);
418         FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
419         FCM_EnvelopeData *fedn;
420         FCM_EnvelopeData fed;
421         
422         /* init template data */
423         fed.min= -1.0f;
424         fed.max= 1.0f;
425         fed.time= (float)scene->r.cfra; // XXX make this int for ease of use?
426         fed.f1= fed.f2= 0;
427         
428         /* check that no data exists for the current frame... */
429         if (env->data) {
430                 short exists = -1;
431                 int i= binarysearch_fcm_envelopedata_index(env->data, (float)(scene->r.cfra), env->totvert, &exists);
432                 
433                 /* binarysearch_...() will set exists by default to 0, so if it is non-zero, that means that the point exists already */
434                 if (exists)
435                         return;
436                         
437                 /* add new */
438                 fedn= MEM_callocN((env->totvert+1)*sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
439                 
440                 /* add the points that should occur before the point to be pasted */
441                 if (i > 0)
442                         memcpy(fedn, env->data, i*sizeof(FCM_EnvelopeData));
443                 
444                 /* add point to paste at index i */
445                 *(fedn + i)= fed;
446                 
447                 /* add the points that occur after the point to be pasted */
448                 if (i < env->totvert) 
449                         memcpy(fedn+i+1, env->data+i, (env->totvert-i)*sizeof(FCM_EnvelopeData));
450                 
451                 /* replace (+ free) old with new */
452                 MEM_freeN(env->data);
453                 env->data= fedn;
454                 
455                 env->totvert++;
456         }
457         else {
458                 env->data= MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
459                 *(env->data)= fed;
460                 
461                 env->totvert= 1;
462         }
463 }
464
465 /* callback to remove envelope data point */
466 // TODO: should we have a separate file for things like this?
467 static void fmod_envelope_deletepoint_cb (bContext *C, void *fcm_dv, void *ind_v)
468 {
469         FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
470         FCM_EnvelopeData *fedn;
471         int index= GET_INT_FROM_POINTER(ind_v);
472         
473         /* check that no data exists for the current frame... */
474         if (env->totvert > 1) {
475                 /* allocate a new smaller array */
476                 fedn= MEM_callocN(sizeof(FCM_EnvelopeData)*(env->totvert-1), "FCM_EnvelopeData");
477                 
478                 memcpy(fedn, &env->data, sizeof(FCM_EnvelopeData)*(index));
479                 memcpy(&fedn[index], &env->data[index+1], sizeof(FCM_EnvelopeData)*(env->totvert-index-1));
480                 
481                 /* free old array, and set the new */
482                 MEM_freeN(env->data);
483                 env->data= fedn;
484                 env->totvert--;
485         }
486         else {
487                 /* just free array, since the only vert was deleted */
488                 if (env->data) 
489                         MEM_freeN(env->data);
490                 env->totvert= 0;
491         }
492 }
493
494 /* draw settings for envelope modifier */
495 static void draw_modifier__envelope(uiBlock *block, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
496 {
497         FMod_Envelope *env= (FMod_Envelope *)fcm->data;
498         FCM_EnvelopeData *fed;
499         uiBut *but;
500         int cy= (*yco - 28);
501         int i;
502         
503         /* set the height:
504          *      - basic settings + variable height from envelope controls
505          */
506         (*height) = 115 + (35 * env->totvert);
507         
508         /* basic settings (backdrop + general settings + some padding) */
509         DRAW_BACKDROP((*height));
510         
511         /* General Settings */
512         uiDefBut(block, LABEL, 1, "Envelope:", 10, cy, 100, 20, NULL, 0.0, 0.0, 0, 0, "Settings for cycling before first keyframe");
513         cy -= 20;
514         
515         uiBlockBeginAlign(block);
516                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Reference Val:", 10, cy, 300, 20, &env->midval, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "");
517                 cy -= 20;
518                 
519                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Min:", 10, cy, 150, 20, &env->min, -UI_FLT_MAX, env->max, 10, 3, "Minimum value (relative to Reference Value) that is used as the 'normal' minimum value");
520                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Max:", 160, cy, 150, 20, &env->max, env->min, UI_FLT_MAX, 10, 3, "Maximum value (relative to Reference Value) that is used as the 'normal' maximum value");
521                 cy -= 35;
522         uiBlockEndAlign(block);
523         
524         
525         /* Points header */
526         uiDefBut(block, LABEL, 1, "Control Points:", 10, cy, 150, 20, NULL, 0.0, 0.0, 0, 0, "");
527         
528         but= uiDefBut(block, BUT, B_FMODIFIER_REDRAW, "Add Point", 160,cy,150,19, NULL, 0, 0, 0, 0, "Adds a new control-point to the envelope on the current frame");
529         uiButSetFunc(but, fmod_envelope_addpoint_cb, env, NULL);
530         cy -= 35;
531         
532         /* Points List */
533         for (i=0, fed=env->data; i < env->totvert; i++, fed++) {
534                 uiBlockBeginAlign(block);
535                         but=uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Fra:", 2, cy, 90, 20, &fed->time, -UI_FLT_MAX, UI_FLT_MAX, 10, 1, "Frame that envelope point occurs");
536                         uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
537                         
538                         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Min:", 92, cy, 100, 20, &fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Minimum bound of envelope at this point");
539                         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Max:", 192, cy, 100, 20, &fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Maximum bound of envelope at this point");
540                         
541                         but= uiDefIconBut(block, BUT, B_FMODIFIER_REDRAW, ICON_X, 292, cy, 18, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Delete envelope control point");
542                         uiButSetFunc(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i));
543                 uiBlockBeginAlign(block);
544                 cy -= 25;
545         }
546 }
547
548 /* --------------- */
549
550 /* draw settings for limits modifier */
551 static void draw_modifier__limits(uiBlock *block, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
552 {
553         FMod_Limits *data= (FMod_Limits *)fcm->data;
554         const int togButWidth = 50;
555         const int textButWidth = ((width/2)-togButWidth);
556         
557         /* set the height */
558         (*height) = 60;
559         
560         /* basic settings (backdrop + some padding) */
561         DRAW_BACKDROP((*height));
562         
563         /* Draw Pairs of LimitToggle+LimitValue */
564         uiBlockBeginAlign(block); 
565                 uiDefButBitI(block, TOGBUT, FCM_LIMIT_XMIN, B_FMODIFIER_REDRAW, "xMin", 5, *yco-30, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x value"); 
566                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 5+togButWidth, *yco-30, (textButWidth-5), 18, &data->rect.xmin, -UI_FLT_MAX, UI_FLT_MAX, 0.1,0.5,"Lowest x value to allow"); 
567         uiBlockEndAlign(block); 
568         
569         uiBlockBeginAlign(block); 
570                 uiDefButBitI(block, TOGBUT, FCM_LIMIT_XMAX, B_FMODIFIER_REDRAW, "XMax", 5+(width-(textButWidth-5)-togButWidth), *yco-30, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum x value"); 
571                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 5+(width-textButWidth-5), *yco-30, (textButWidth-5), 18, &data->rect.xmax, -UI_FLT_MAX, UI_FLT_MAX, 0.1,0.5,"Highest x value to allow"); 
572         uiBlockEndAlign(block); 
573         
574         uiBlockBeginAlign(block); 
575                 uiDefButBitI(block, TOGBUT, FCM_LIMIT_YMIN, B_FMODIFIER_REDRAW, "yMin", 5, *yco-52, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y value"); 
576                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 5+togButWidth, *yco-52, (textButWidth-5), 18, &data->rect.ymin, -UI_FLT_MAX, UI_FLT_MAX, 0.1,0.5,"Lowest y value to allow"); 
577         uiBlockEndAlign(block);
578         
579         uiBlockBeginAlign(block); 
580                 uiDefButBitI(block, TOGBUT, FCM_LIMIT_YMAX, B_FMODIFIER_REDRAW, "YMax", 5+(width-(textButWidth-5)-togButWidth), *yco-52, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum y value"); 
581                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 5+(width-textButWidth-5), *yco-52, (textButWidth-5), 18, &data->rect.ymax, -UI_FLT_MAX, UI_FLT_MAX, 0.1,0.5,"Highest y value to allow"); 
582         uiBlockEndAlign(block); 
583 }
584
585 /* --------------- */
586
587 // FIXME: remove dependency for F-Curve
588 void ANIM_uiTemplate_fmodifier_draw (uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco)
589 {
590         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
591         uiBut *but;
592         short active= (fcm->flag & FMODIFIER_FLAG_ACTIVE);
593         short width= 314;
594         short height = 0; 
595         int rb_col;
596         
597         /* draw header */
598         {
599                 uiBlockSetEmboss(block, UI_EMBOSSN);
600                 
601                 /* rounded header */
602                 rb_col= (active)?-20:20;
603                 but= uiDefBut(block, ROUNDBOX, B_REDR, "", 0, *yco-2, width, 24, NULL, 5.0, 0.0, 15.0, (float)(rb_col-20), ""); 
604                 
605                 /* expand */
606                 uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_EXPANDED, B_REDR, ICON_TRIA_RIGHT,      5, *yco-1, 20, 20, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is expanded.");
607                 
608                 /* checkbox for 'active' status (for now) */
609                 but= uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_ACTIVE, B_REDR, ICON_RADIOBUT_OFF, 25, *yco-1, 20, 20, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is active one.");
610                 uiButSetFunc(but, activate_fmodifier_cb, fcu, fcm);
611                 
612                 /* name */
613                 if (fmi)
614                         uiDefBut(block, LABEL, 1, fmi->name,    10+40, *yco, 150, 20, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type. Click to make modifier active one.");
615                 else
616                         uiDefBut(block, LABEL, 1, "<Unknown Modifier>", 10+40, *yco, 150, 20, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type. Click to make modifier active one.");
617                 
618                 /* 'mute' button */
619                 uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_MUTED, B_REDR, ICON_MUTE_IPO_OFF,       10+(width-60), *yco-1, 20, 20, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is temporarily muted (not evaluated).");
620                 
621                 /* delete button */
622                 but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 10+(width-30), *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Delete F-Curve Modifier.");
623                 uiButSetFunc(but, delete_fmodifier_cb, fcu, fcm);
624                 
625                 uiBlockSetEmboss(block, UI_EMBOSS);
626         }
627         
628         /* when modifier is expanded, draw settings */
629         if (fcm->flag & FMODIFIER_FLAG_EXPANDED) {
630                 /* draw settings for individual modifiers */
631                 switch (fcm->type) {
632                         case FMODIFIER_TYPE_GENERATOR: /* Generator */
633                                 draw_modifier__generator(block, fcm, yco, &height, width, active, rb_col);
634                                 break;
635                                 
636                         case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */
637                                 draw_modifier__fn_generator(block, fcm, yco, &height, width, active, rb_col);
638                                 break;
639                                 
640                         case FMODIFIER_TYPE_CYCLES: /* Cycles */
641                                 draw_modifier__cycles(block, fcm, yco, &height, width, active, rb_col);
642                                 break;
643                                 
644                         case FMODIFIER_TYPE_ENVELOPE: /* Envelope */
645                                 draw_modifier__envelope(block, fcm, yco, &height, width, active, rb_col);
646                                 break;
647                                 
648                         case FMODIFIER_TYPE_LIMITS: /* Limits */
649                                 draw_modifier__limits(block, fcm, yco, &height, width, active, rb_col);
650                                 break;
651                         
652                         case FMODIFIER_TYPE_NOISE: /* Noise */
653                                 draw_modifier__noise(block, fcm, yco, &height, width, active, rb_col);
654                                 break;
655                         
656                         default: /* unknown type */
657                                 height= 96;
658                                 //DRAW_BACKDROP(height); // XXX buggy...
659                                 break;
660                 }
661         }
662         
663         /* adjust height for new to start */
664         (*yco) -= (height + 27); 
665 }
666
667 /* ********************************************** */
668
669