9e96023b2724fbb0f839a0c571ae7c107e14a8ab
[blender.git] / source / blender / editors / animation / fmodifier_ui.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edanimation
22  */
23
24 /* User-Interface Stuff for F-Modifiers:
25  * This file defines the (C-Coded) templates + editing callbacks needed
26  * by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor,
27  * and NLA-Strips in the NLA Editor.
28  *
29  * Copy/Paste Buffer for F-Modifiers:
30  * For now, this is also defined in this file so that it can be shared between the
31  */
32
33 #include <string.h>
34
35 #include "DNA_anim_types.h"
36 #include "DNA_scene_types.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLT_translation.h"
41
42 #include "BLI_blenlib.h"
43 #include "BLI_utildefines.h"
44
45 #include "BKE_animsys.h"
46 #include "BKE_context.h"
47 #include "BKE_fcurve.h"
48
49 #include "WM_api.h"
50 #include "WM_types.h"
51
52 #include "RNA_access.h"
53
54 #include "UI_interface.h"
55 #include "UI_resources.h"
56
57 #include "ED_anim_api.h"
58 #include "ED_undo.h"
59
60 #include "DEG_depsgraph.h"
61
62 /* ********************************************** */
63 /* UI STUFF */
64
65 // XXX! --------------------------------
66 /* Temporary definition for limits of float number buttons
67  * (FLT_MAX tends to infinity with old system). */
68 #define UI_FLT_MAX 10000.0f
69
70 #define B_REDR 1
71 #define B_FMODIFIER_REDRAW 20
72
73 /* callback to verify modifier data */
74 static void validate_fmodifier_cb(bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg))
75 {
76   FModifier *fcm = (FModifier *)fcm_v;
77   const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
78
79   /* call the verify callback on the modifier if applicable */
80   if (fmi && fmi->verify_data)
81     fmi->verify_data(fcm);
82 }
83
84 /* callback to remove the given modifier  */
85 typedef struct FModifierDeleteContext {
86   ID *fcurve_owner_id;
87   ListBase *modifiers;
88 } FModifierDeleteContext;
89 static void delete_fmodifier_cb(bContext *C, void *ctx_v, void *fcm_v)
90 {
91   FModifierDeleteContext *ctx = (FModifierDeleteContext *)ctx_v;
92   ListBase *modifiers = ctx->modifiers;
93   FModifier *fcm = (FModifier *)fcm_v;
94
95   /* remove the given F-Modifier from the active modifier-stack */
96   remove_fmodifier(modifiers, fcm);
97
98   ED_undo_push(C, "Delete F-Curve Modifier");
99
100   /* send notifiers */
101   /* XXX for now, this is the only way to get updates in all the right places...
102    * but would be nice to have a special one in this case. */
103   WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
104   DEG_id_tag_update(ctx->fcurve_owner_id, ID_RECALC_ANIMATION);
105 }
106
107 /* --------------- */
108
109 /* draw settings for generator modifier */
110 static void draw_modifier__generator(uiLayout *layout,
111                                      ID *fcurve_owner_id,
112                                      FModifier *fcm,
113                                      short width)
114 {
115   FMod_Generator *data = (FMod_Generator *)fcm->data;
116   uiLayout /* *col, */ /* UNUSED */ *row;
117   uiBlock *block;
118   uiBut *but;
119   PointerRNA ptr;
120   short bwidth = width - 1.5 * UI_UNIT_X; /* max button width */
121
122   /* init the RNA-pointer */
123   RNA_pointer_create(fcurve_owner_id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
124
125   /* basic settings (backdrop + mode selector + some padding) */
126   /* col = uiLayoutColumn(layout, true); */ /* UNUSED */
127   block = uiLayoutGetBlock(layout);
128   UI_block_align_begin(block);
129   but = uiDefButR(block,
130                   UI_BTYPE_MENU,
131                   B_FMODIFIER_REDRAW,
132                   NULL,
133                   0,
134                   0,
135                   bwidth,
136                   UI_UNIT_Y,
137                   &ptr,
138                   "mode",
139                   -1,
140                   0,
141                   0,
142                   -1,
143                   -1,
144                   NULL);
145   UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
146
147   uiDefButR(block,
148             UI_BTYPE_TOGGLE,
149             B_FMODIFIER_REDRAW,
150             NULL,
151             0,
152             0,
153             bwidth,
154             UI_UNIT_Y,
155             &ptr,
156             "use_additive",
157             -1,
158             0,
159             0,
160             -1,
161             -1,
162             NULL);
163   UI_block_align_end(block);
164
165   /* now add settings for individual modes */
166   switch (data->mode) {
167     case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
168     {
169       const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
170       float *cp = NULL;
171       char xval[32];
172       unsigned int i;
173       int maxXWidth;
174
175       /* draw polynomial order selector */
176       row = uiLayoutRow(layout, false);
177       block = uiLayoutGetBlock(row);
178       but = uiDefButI(
179           block,
180           UI_BTYPE_NUM,
181           B_FMODIFIER_REDRAW,
182           IFACE_("Poly Order:"),
183           0.5f * UI_UNIT_X,
184           0,
185           bwidth,
186           UI_UNIT_Y,
187           &data->poly_order,
188           1,
189           100,
190           0,
191           0,
192           TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
193       UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
194
195       /* calculate maximum width of label for "x^n" labels */
196       if (data->arraysize > 2) {
197         BLI_snprintf(xval, sizeof(xval), "x^%u", data->arraysize);
198         /* XXX: UI_fontstyle_string_width is not accurate */
199         maxXWidth = UI_fontstyle_string_width(fstyle, xval) + 0.5 * UI_UNIT_X;
200       }
201       else {
202         /* basic size (just "x") */
203         maxXWidth = UI_fontstyle_string_width(fstyle, "x") + 0.5 * UI_UNIT_X;
204       }
205
206       /* draw controls for each coefficient and a + sign at end of row */
207       row = uiLayoutRow(layout, true);
208       block = uiLayoutGetBlock(row);
209
210       cp = data->coefficients;
211       for (i = 0; (i < data->arraysize) && (cp); i++, cp++) {
212         /* To align with first line... */
213         if (i)
214           uiDefBut(block,
215                    UI_BTYPE_LABEL,
216                    1,
217                    "   ",
218                    0,
219                    0,
220                    2 * UI_UNIT_X,
221                    UI_UNIT_Y,
222                    NULL,
223                    0.0,
224                    0.0,
225                    0,
226                    0,
227                    "");
228         else
229           uiDefBut(block,
230                    UI_BTYPE_LABEL,
231                    1,
232                    "y =",
233                    0,
234                    0,
235                    2 * UI_UNIT_X,
236                    UI_UNIT_Y,
237                    NULL,
238                    0.0,
239                    0.0,
240                    0,
241                    0,
242                    "");
243
244         /* coefficient */
245         uiDefButF(block,
246                   UI_BTYPE_NUM,
247                   B_FMODIFIER_REDRAW,
248                   "",
249                   0,
250                   0,
251                   bwidth / 2,
252                   UI_UNIT_Y,
253                   cp,
254                   -UI_FLT_MAX,
255                   UI_FLT_MAX,
256                   10,
257                   3,
258                   TIP_("Coefficient for polynomial"));
259
260         /* 'x' param (and '+' if necessary) */
261         if (i == 0)
262           BLI_strncpy(xval, "", sizeof(xval));
263         else if (i == 1)
264           BLI_strncpy(xval, "x", sizeof(xval));
265         else
266           BLI_snprintf(xval, sizeof(xval), "x^%u", i);
267         uiDefBut(block,
268                  UI_BTYPE_LABEL,
269                  1,
270                  xval,
271                  0,
272                  0,
273                  maxXWidth,
274                  UI_UNIT_Y,
275                  NULL,
276                  0.0,
277                  0.0,
278                  0,
279                  0,
280                  TIP_("Power of x"));
281
282         if ((i != (data->arraysize - 1)) || ((i == 0) && data->arraysize == 2)) {
283           uiDefBut(
284               block, UI_BTYPE_LABEL, 1, "+", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
285
286           /* next coefficient on a new row */
287           row = uiLayoutRow(layout, true);
288           block = uiLayoutGetBlock(row);
289         }
290         else {
291           /* For alignment in UI! */
292           uiDefBut(
293               block, UI_BTYPE_LABEL, 1, " ", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
294         }
295       }
296       break;
297     }
298
299     case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial expression */
300     {
301       float *cp = NULL;
302       unsigned int i;
303
304       /* draw polynomial order selector */
305       row = uiLayoutRow(layout, false);
306       block = uiLayoutGetBlock(row);
307       but = uiDefButI(
308           block,
309           UI_BTYPE_NUM,
310           B_FMODIFIER_REDRAW,
311           IFACE_("Poly Order:"),
312           0,
313           0,
314           width - 1.5 * UI_UNIT_X,
315           UI_UNIT_Y,
316           &data->poly_order,
317           1,
318           100,
319           0,
320           0,
321           TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
322       UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
323
324       /* draw controls for each pair of coefficients */
325       row = uiLayoutRow(layout, true);
326       block = uiLayoutGetBlock(row);
327
328       cp = data->coefficients;
329       for (i = 0; (i < data->poly_order) && (cp); i++, cp += 2) {
330         /* To align with first line */
331         if (i)
332           uiDefBut(block,
333                    UI_BTYPE_LABEL,
334                    1,
335                    "   ",
336                    0,
337                    0,
338                    2.5 * UI_UNIT_X,
339                    UI_UNIT_Y,
340                    NULL,
341                    0.0,
342                    0.0,
343                    0,
344                    0,
345                    "");
346         else
347           uiDefBut(block,
348                    UI_BTYPE_LABEL,
349                    1,
350                    "y =",
351                    0,
352                    0,
353                    2.5 * UI_UNIT_X,
354                    UI_UNIT_Y,
355                    NULL,
356                    0.0,
357                    0.0,
358                    0,
359                    0,
360                    "");
361         /* opening bracket */
362         uiDefBut(
363             block, UI_BTYPE_LABEL, 1, "(", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
364
365         /* coefficients */
366         uiDefButF(block,
367                   UI_BTYPE_NUM,
368                   B_FMODIFIER_REDRAW,
369                   "",
370                   0,
371                   0,
372                   5 * UI_UNIT_X,
373                   UI_UNIT_Y,
374                   cp,
375                   -UI_FLT_MAX,
376                   UI_FLT_MAX,
377                   10,
378                   3,
379                   TIP_("Coefficient of x"));
380
381         uiDefBut(block,
382                  UI_BTYPE_LABEL,
383                  1,
384                  "x +",
385                  0,
386                  0,
387                  2 * UI_UNIT_X,
388                  UI_UNIT_Y,
389                  NULL,
390                  0.0,
391                  0.0,
392                  0,
393                  0,
394                  "");
395
396         uiDefButF(block,
397                   UI_BTYPE_NUM,
398                   B_FMODIFIER_REDRAW,
399                   "",
400                   0,
401                   0,
402                   5 * UI_UNIT_X,
403                   UI_UNIT_Y,
404                   cp + 1,
405                   -UI_FLT_MAX,
406                   UI_FLT_MAX,
407                   10,
408                   3,
409                   TIP_("Second coefficient"));
410
411         /* closing bracket and multiplication sign */
412         if ((i != (data->poly_order - 1)) || ((i == 0) && data->poly_order == 2)) {
413           uiDefBut(block,
414                    UI_BTYPE_LABEL,
415                    1,
416                    ") \xc3\x97",
417                    0,
418                    0,
419                    2 * UI_UNIT_X,
420                    UI_UNIT_Y,
421                    NULL,
422                    0.0,
423                    0.0,
424                    0,
425                    0,
426                    "");
427
428           /* set up new row for the next pair of coefficients */
429           row = uiLayoutRow(layout, true);
430           block = uiLayoutGetBlock(row);
431         }
432         else
433           uiDefBut(block,
434                    UI_BTYPE_LABEL,
435                    1,
436                    ")  ",
437                    0,
438                    0,
439                    2 * UI_UNIT_X,
440                    UI_UNIT_Y,
441                    NULL,
442                    0.0,
443                    0.0,
444                    0,
445                    0,
446                    "");
447       }
448       break;
449     }
450   }
451 }
452
453 /* --------------- */
454
455 /* draw settings for generator modifier */
456 static void draw_modifier__fn_generator(uiLayout *layout,
457                                         ID *fcurve_owner_id,
458                                         FModifier *fcm,
459                                         short UNUSED(width))
460 {
461   uiLayout *col;
462   PointerRNA ptr;
463
464   /* init the RNA-pointer */
465   RNA_pointer_create(fcurve_owner_id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
466
467   /* add the settings */
468   col = uiLayoutColumn(layout, true);
469   uiItemR(col, &ptr, "function_type", 0, "", ICON_NONE);
470   uiItemR(col, &ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
471
472   col = uiLayoutColumn(layout, false);  // no grouping for now
473   uiItemR(col, &ptr, "amplitude", 0, NULL, ICON_NONE);
474   uiItemR(col, &ptr, "phase_multiplier", 0, NULL, ICON_NONE);
475   uiItemR(col, &ptr, "phase_offset", 0, NULL, ICON_NONE);
476   uiItemR(col, &ptr, "value_offset", 0, NULL, ICON_NONE);
477 }
478
479 /* --------------- */
480
481 /* draw settings for cycles modifier */
482 static void draw_modifier__cycles(uiLayout *layout,
483                                   ID *fcurve_owner_id,
484                                   FModifier *fcm,
485                                   short UNUSED(width))
486 {
487   uiLayout *split, *col;
488   PointerRNA ptr;
489
490   /* init the RNA-pointer */
491   RNA_pointer_create(fcurve_owner_id, &RNA_FModifierCycles, fcm, &ptr);
492
493   /* split into 2 columns
494    * NOTE: the mode comboboxes shouldn't get labels, otherwise there isn't enough room
495    */
496   split = uiLayoutSplit(layout, 0.5f, false);
497
498   /* before range */
499   col = uiLayoutColumn(split, true);
500   uiItemL(col, IFACE_("Before:"), ICON_NONE);
501   uiItemR(col, &ptr, "mode_before", 0, "", ICON_NONE);
502   uiItemR(col, &ptr, "cycles_before", 0, NULL, ICON_NONE);
503
504   /* after range */
505   col = uiLayoutColumn(split, true);
506   uiItemL(col, IFACE_("After:"), ICON_NONE);
507   uiItemR(col, &ptr, "mode_after", 0, "", ICON_NONE);
508   uiItemR(col, &ptr, "cycles_after", 0, NULL, ICON_NONE);
509 }
510
511 /* --------------- */
512
513 /* draw settings for noise modifier */
514 static void draw_modifier__noise(uiLayout *layout,
515                                  ID *fcurve_owner_id,
516                                  FModifier *fcm,
517                                  short UNUSED(width))
518 {
519   uiLayout *split, *col;
520   PointerRNA ptr;
521
522   /* init the RNA-pointer */
523   RNA_pointer_create(fcurve_owner_id, &RNA_FModifierNoise, fcm, &ptr);
524
525   /* blending mode */
526   uiItemR(layout, &ptr, "blend_type", 0, NULL, ICON_NONE);
527
528   /* split into 2 columns */
529   split = uiLayoutSplit(layout, 0.5f, false);
530
531   /* col 1 */
532   col = uiLayoutColumn(split, false);
533   uiItemR(col, &ptr, "scale", 0, NULL, ICON_NONE);
534   uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE);
535   uiItemR(col, &ptr, "offset", 0, NULL, ICON_NONE);
536
537   /* col 2 */
538   col = uiLayoutColumn(split, false);
539   uiItemR(col, &ptr, "phase", 0, NULL, ICON_NONE);
540   uiItemR(col, &ptr, "depth", 0, NULL, ICON_NONE);
541 }
542
543 /* callback to add new envelope data point */
544 static void fmod_envelope_addpoint_cb(bContext *C, void *fcm_dv, void *UNUSED(arg))
545 {
546   Scene *scene = CTX_data_scene(C);
547   FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
548   FCM_EnvelopeData *fedn;
549   FCM_EnvelopeData fed;
550
551   /* init template data */
552   fed.min = -1.0f;
553   fed.max = 1.0f;
554   fed.time = (float)scene->r.cfra;  // XXX make this int for ease of use?
555   fed.f1 = fed.f2 = 0;
556
557   /* check that no data exists for the current frame... */
558   if (env->data) {
559     bool exists;
560     int i = BKE_fcm_envelope_find_index(env->data, (float)(scene->r.cfra), env->totvert, &exists);
561
562     /* binarysearch_...() will set exists by default to 0,
563      * so if it is non-zero, that means that the point exists already */
564     if (exists) {
565       return;
566     }
567
568     /* add new */
569     fedn = MEM_callocN((env->totvert + 1) * sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
570
571     /* add the points that should occur before the point to be pasted */
572     if (i > 0)
573       memcpy(fedn, env->data, i * sizeof(FCM_EnvelopeData));
574
575     /* add point to paste at index i */
576     *(fedn + i) = fed;
577
578     /* add the points that occur after the point to be pasted */
579     if (i < env->totvert)
580       memcpy(fedn + i + 1, env->data + i, (env->totvert - i) * sizeof(FCM_EnvelopeData));
581
582     /* replace (+ free) old with new */
583     MEM_freeN(env->data);
584     env->data = fedn;
585
586     env->totvert++;
587   }
588   else {
589     env->data = MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
590     *(env->data) = fed;
591
592     env->totvert = 1;
593   }
594 }
595
596 /* callback to remove envelope data point */
597 // TODO: should we have a separate file for things like this?
598 static void fmod_envelope_deletepoint_cb(bContext *UNUSED(C), void *fcm_dv, void *ind_v)
599 {
600   FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
601   FCM_EnvelopeData *fedn;
602   int index = POINTER_AS_INT(ind_v);
603
604   /* check that no data exists for the current frame... */
605   if (env->totvert > 1) {
606     /* allocate a new smaller array */
607     fedn = MEM_callocN(sizeof(FCM_EnvelopeData) * (env->totvert - 1), "FCM_EnvelopeData");
608
609     memcpy(fedn, env->data, sizeof(FCM_EnvelopeData) * (index));
610     memcpy(fedn + index,
611            env->data + (index + 1),
612            sizeof(FCM_EnvelopeData) * ((env->totvert - index) - 1));
613
614     /* free old array, and set the new */
615     MEM_freeN(env->data);
616     env->data = fedn;
617     env->totvert--;
618   }
619   else {
620     /* just free array, since the only vert was deleted */
621     if (env->data) {
622       MEM_freeN(env->data);
623       env->data = NULL;
624     }
625     env->totvert = 0;
626   }
627 }
628
629 /* draw settings for envelope modifier */
630 static void draw_modifier__envelope(uiLayout *layout,
631                                     ID *fcurve_owner_id,
632                                     FModifier *fcm,
633                                     short UNUSED(width))
634 {
635   FMod_Envelope *env = (FMod_Envelope *)fcm->data;
636   FCM_EnvelopeData *fed;
637   uiLayout *col, *row;
638   uiBlock *block;
639   uiBut *but;
640   PointerRNA ptr;
641   int i;
642
643   /* init the RNA-pointer */
644   RNA_pointer_create(fcurve_owner_id, &RNA_FModifierEnvelope, fcm, &ptr);
645
646   /* general settings */
647   col = uiLayoutColumn(layout, true);
648   uiItemL(col, IFACE_("Envelope:"), ICON_NONE);
649   uiItemR(col, &ptr, "reference_value", 0, NULL, ICON_NONE);
650
651   row = uiLayoutRow(col, true);
652   uiItemR(row, &ptr, "default_min", 0, IFACE_("Min"), ICON_NONE);
653   uiItemR(row, &ptr, "default_max", 0, IFACE_("Max"), ICON_NONE);
654
655   /* control points header */
656   /* TODO: move this control-point control stuff to using the new special widgets for lists
657    * the current way is far too cramped */
658   row = uiLayoutRow(layout, false);
659   block = uiLayoutGetBlock(row);
660
661   uiDefBut(block,
662            UI_BTYPE_LABEL,
663            1,
664            IFACE_("Control Points:"),
665            0,
666            0,
667            7.5 * UI_UNIT_X,
668            UI_UNIT_Y,
669            NULL,
670            0.0,
671            0.0,
672            0,
673            0,
674            "");
675
676   but = uiDefBut(block,
677                  UI_BTYPE_BUT,
678                  B_FMODIFIER_REDRAW,
679                  IFACE_("Add Point"),
680                  0,
681                  0,
682                  7.5 * UI_UNIT_X,
683                  UI_UNIT_Y,
684                  NULL,
685                  0,
686                  0,
687                  0,
688                  0,
689                  TIP_("Add a new control-point to the envelope on the current frame"));
690   UI_but_func_set(but, fmod_envelope_addpoint_cb, env, NULL);
691
692   /* control points list */
693   for (i = 0, fed = env->data; i < env->totvert; i++, fed++) {
694     /* get a new row to operate on */
695     row = uiLayoutRow(layout, true);
696     block = uiLayoutGetBlock(row);
697
698     UI_block_align_begin(block);
699     but = uiDefButF(block,
700                     UI_BTYPE_NUM,
701                     B_FMODIFIER_REDRAW,
702                     IFACE_("Fra:"),
703                     0,
704                     0,
705                     4.5 * UI_UNIT_X,
706                     UI_UNIT_Y,
707                     &fed->time,
708                     -MAXFRAMEF,
709                     MAXFRAMEF,
710                     10,
711                     1,
712                     TIP_("Frame that envelope point occurs"));
713     UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
714
715     uiDefButF(block,
716               UI_BTYPE_NUM,
717               B_FMODIFIER_REDRAW,
718               IFACE_("Min:"),
719               0,
720               0,
721               5 * UI_UNIT_X,
722               UI_UNIT_Y,
723               &fed->min,
724               -UI_FLT_MAX,
725               UI_FLT_MAX,
726               10,
727               2,
728               TIP_("Minimum bound of envelope at this point"));
729     uiDefButF(block,
730               UI_BTYPE_NUM,
731               B_FMODIFIER_REDRAW,
732               IFACE_("Max:"),
733               0,
734               0,
735               5 * UI_UNIT_X,
736               UI_UNIT_Y,
737               &fed->max,
738               -UI_FLT_MAX,
739               UI_FLT_MAX,
740               10,
741               2,
742               TIP_("Maximum bound of envelope at this point"));
743
744     but = uiDefIconBut(block,
745                        UI_BTYPE_BUT,
746                        B_FMODIFIER_REDRAW,
747                        ICON_X,
748                        0,
749                        0,
750                        0.9 * UI_UNIT_X,
751                        UI_UNIT_Y,
752                        NULL,
753                        0.0,
754                        0.0,
755                        0.0,
756                        0.0,
757                        TIP_("Delete envelope control point"));
758     UI_but_func_set(but, fmod_envelope_deletepoint_cb, env, POINTER_FROM_INT(i));
759     UI_block_align_begin(block);
760   }
761 }
762
763 /* --------------- */
764
765 /* draw settings for limits modifier */
766 static void draw_modifier__limits(uiLayout *layout,
767                                   ID *fcurve_owner_id,
768                                   FModifier *fcm,
769                                   short UNUSED(width))
770 {
771   uiLayout *split, *col /* , *row */ /* UNUSED */;
772   PointerRNA ptr;
773
774   /* init the RNA-pointer */
775   RNA_pointer_create(fcurve_owner_id, &RNA_FModifierLimits, fcm, &ptr);
776
777   /* row 1: minimum */
778   {
779     /* row = uiLayoutRow(layout, false); */ /* UNUSED */
780
781     /* split into 2 columns */
782     split = uiLayoutSplit(layout, 0.5f, false);
783
784     /* x-minimum */
785     col = uiLayoutColumn(split, true);
786     uiItemR(col, &ptr, "use_min_x", 0, NULL, ICON_NONE);
787     uiItemR(col, &ptr, "min_x", 0, NULL, ICON_NONE);
788
789     /* y-minimum*/
790     col = uiLayoutColumn(split, true);
791     uiItemR(col, &ptr, "use_min_y", 0, NULL, ICON_NONE);
792     uiItemR(col, &ptr, "min_y", 0, NULL, ICON_NONE);
793   }
794
795   /* row 2: maximum */
796   {
797     /* row = uiLayoutRow(layout, false); */ /* UNUSED */
798
799     /* split into 2 columns */
800     split = uiLayoutSplit(layout, 0.5f, false);
801
802     /* x-minimum */
803     col = uiLayoutColumn(split, true);
804     uiItemR(col, &ptr, "use_max_x", 0, NULL, ICON_NONE);
805     uiItemR(col, &ptr, "max_x", 0, NULL, ICON_NONE);
806
807     /* y-minimum*/
808     col = uiLayoutColumn(split, true);
809     uiItemR(col, &ptr, "use_max_y", 0, NULL, ICON_NONE);
810     uiItemR(col, &ptr, "max_y", 0, NULL, ICON_NONE);
811   }
812 }
813
814 /* --------------- */
815
816 /* draw settings for stepped interpolation modifier */
817 static void draw_modifier__stepped(uiLayout *layout,
818                                    ID *fcurve_owner_id,
819                                    FModifier *fcm,
820                                    short UNUSED(width))
821 {
822   uiLayout *col, *sub;
823   PointerRNA ptr;
824
825   /* init the RNA-pointer */
826   RNA_pointer_create(fcurve_owner_id, &RNA_FModifierStepped, fcm, &ptr);
827
828   /* block 1: "stepping" settings */
829   col = uiLayoutColumn(layout, false);
830   uiItemR(col, &ptr, "frame_step", 0, NULL, ICON_NONE);
831   uiItemR(col, &ptr, "frame_offset", 0, NULL, ICON_NONE);
832
833   /* block 2: start range settings */
834   col = uiLayoutColumn(layout, true);
835   uiItemR(col, &ptr, "use_frame_start", 0, NULL, ICON_NONE);
836
837   sub = uiLayoutColumn(col, true);
838   uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_start"));
839   uiItemR(sub, &ptr, "frame_start", 0, NULL, ICON_NONE);
840
841   /* block 3: end range settings */
842   col = uiLayoutColumn(layout, true);
843   uiItemR(col, &ptr, "use_frame_end", 0, NULL, ICON_NONE);
844
845   sub = uiLayoutColumn(col, true);
846   uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_end"));
847   uiItemR(sub, &ptr, "frame_end", 0, NULL, ICON_NONE);
848 }
849
850 /* --------------- */
851
852 void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout,
853                                     ID *fcurve_owner_id,
854                                     ListBase *modifiers,
855                                     FModifier *fcm)
856 {
857   const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
858   uiLayout *box, *row, *sub, *col;
859   uiBlock *block;
860   uiBut *but;
861   short width = 314;
862   PointerRNA ptr;
863
864   /* init the RNA-pointer */
865   RNA_pointer_create(fcurve_owner_id, &RNA_FModifier, fcm, &ptr);
866
867   /* draw header */
868   {
869     /* get layout-row + UI-block for this */
870     box = uiLayoutBox(layout);
871
872     row = uiLayoutRow(box, false);
873     block = uiLayoutGetBlock(row);  // err...
874
875     /* left-align -------------------------------------------- */
876     sub = uiLayoutRow(row, true);
877     uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
878
879     UI_block_emboss_set(block, UI_EMBOSS_NONE);
880
881     /* expand */
882     uiItemR(sub, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
883
884     /* checkbox for 'active' status (for now) */
885     uiItemR(sub, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
886
887     /* name */
888     if (fmi)
889       uiItemL(sub, IFACE_(fmi->name), ICON_NONE);
890     else
891       uiItemL(sub, IFACE_("<Unknown Modifier>"), ICON_NONE);
892
893     /* right-align ------------------------------------------- */
894     sub = uiLayoutRow(row, true);
895     uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
896
897     /* 'mute' button */
898     uiItemR(sub, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
899
900     UI_block_emboss_set(block, UI_EMBOSS_NONE);
901
902     /* delete button */
903     but = uiDefIconBut(block,
904                        UI_BTYPE_BUT,
905                        B_REDR,
906                        ICON_X,
907                        0,
908                        0,
909                        UI_UNIT_X,
910                        UI_UNIT_Y,
911                        NULL,
912                        0.0,
913                        0.0,
914                        0.0,
915                        0.0,
916                        TIP_("Delete F-Curve Modifier"));
917     FModifierDeleteContext *ctx = MEM_mallocN(sizeof(FModifierDeleteContext), "fmodifier ctx");
918     ctx->fcurve_owner_id = fcurve_owner_id;
919     ctx->modifiers = modifiers;
920     UI_but_funcN_set(but, delete_fmodifier_cb, ctx, fcm);
921
922     UI_block_emboss_set(block, UI_EMBOSS);
923   }
924
925   /* when modifier is expanded, draw settings */
926   if (fcm->flag & FMODIFIER_FLAG_EXPANDED) {
927     /* set up the flexible-box layout which acts as the backdrop for the modifier settings */
928     box = uiLayoutBox(layout);
929
930     /* draw settings for individual modifiers */
931     switch (fcm->type) {
932       case FMODIFIER_TYPE_GENERATOR: /* Generator */
933         draw_modifier__generator(box, fcurve_owner_id, fcm, width);
934         break;
935
936       case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */
937         draw_modifier__fn_generator(box, fcurve_owner_id, fcm, width);
938         break;
939
940       case FMODIFIER_TYPE_CYCLES: /* Cycles */
941         draw_modifier__cycles(box, fcurve_owner_id, fcm, width);
942         break;
943
944       case FMODIFIER_TYPE_ENVELOPE: /* Envelope */
945         draw_modifier__envelope(box, fcurve_owner_id, fcm, width);
946         break;
947
948       case FMODIFIER_TYPE_LIMITS: /* Limits */
949         draw_modifier__limits(box, fcurve_owner_id, fcm, width);
950         break;
951
952       case FMODIFIER_TYPE_NOISE: /* Noise */
953         draw_modifier__noise(box, fcurve_owner_id, fcm, width);
954         break;
955
956       case FMODIFIER_TYPE_STEPPED: /* Stepped */
957         draw_modifier__stepped(box, fcurve_owner_id, fcm, width);
958         break;
959
960       default: /* unknown type */
961         break;
962     }
963
964     /* one last panel below this: FModifier range */
965     // TODO: experiment with placement of this
966     {
967       box = uiLayoutBox(layout);
968
969       /* restricted range ----------------------------------------------------- */
970       col = uiLayoutColumn(box, true);
971
972       /* top row: use restricted range */
973       row = uiLayoutRow(col, true);
974       uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE);
975
976       if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
977         /* second row: settings */
978         row = uiLayoutRow(col, true);
979
980         uiItemR(row, &ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE);
981         uiItemR(row, &ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
982
983         /* third row: blending influence */
984         row = uiLayoutRow(col, true);
985
986         uiItemR(row, &ptr, "blend_in", 0, IFACE_("In"), ICON_NONE);
987         uiItemR(row, &ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE);
988       }
989
990       /* influence -------------------------------------------------------------- */
991       col = uiLayoutColumn(box, true);
992
993       /* top row: use influence */
994       uiItemR(col, &ptr, "use_influence", 0, NULL, ICON_NONE);
995
996       if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE) {
997         /* second row: influence value */
998         uiItemR(col, &ptr, "influence", 0, NULL, ICON_NONE);
999       }
1000     }
1001   }
1002 }
1003
1004 /* ********************************************** */
1005 /* COPY/PASTE BUFFER STUFF */
1006
1007 /* Copy/Paste Buffer itself (list of FModifier 's) */
1008 static ListBase fmodifier_copypaste_buf = {NULL, NULL};
1009
1010 /* ---------- */
1011
1012 /* free the copy/paste buffer */
1013 void ANIM_fmodifiers_copybuf_free(void)
1014 {
1015   /* just free the whole buffer */
1016   free_fmodifiers(&fmodifier_copypaste_buf);
1017 }
1018
1019 /* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
1020  * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
1021  * - active: only copy the active modifier
1022  */
1023 bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
1024 {
1025   bool ok = true;
1026
1027   /* sanity checks */
1028   if (ELEM(NULL, modifiers, modifiers->first))
1029     return 0;
1030
1031   /* copy the whole list, or just the active one? */
1032   if (active) {
1033     FModifier *fcm = find_active_fmodifier(modifiers);
1034
1035     if (fcm) {
1036       FModifier *fcmN = copy_fmodifier(fcm);
1037       BLI_addtail(&fmodifier_copypaste_buf, fcmN);
1038     }
1039     else
1040       ok = 0;
1041   }
1042   else
1043     copy_fmodifiers(&fmodifier_copypaste_buf, modifiers);
1044
1045   /* did we succeed? */
1046   return ok;
1047 }
1048
1049 /* 'Paste' the F-Modifier(s) from the buffer to the specified list
1050  * - replace: free all the existing modifiers to leave only the pasted ones
1051  */
1052 bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
1053 {
1054   FModifier *fcm;
1055   bool ok = false;
1056
1057   /* sanity checks */
1058   if (modifiers == NULL)
1059     return 0;
1060
1061   bool was_cyclic = curve && BKE_fcurve_is_cyclic(curve);
1062
1063   /* if replacing the list, free the existing modifiers */
1064   if (replace)
1065     free_fmodifiers(modifiers);
1066
1067   /* now copy over all the modifiers in the buffer to the end of the list */
1068   for (fcm = fmodifier_copypaste_buf.first; fcm; fcm = fcm->next) {
1069     /* make a copy of it */
1070     FModifier *fcmN = copy_fmodifier(fcm);
1071
1072     fcmN->curve = curve;
1073
1074     /* make sure the new one isn't active, otherwise the list may get several actives */
1075     fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE;
1076
1077     /* now add it to the end of the list */
1078     BLI_addtail(modifiers, fcmN);
1079     ok = 1;
1080   }
1081
1082   /* adding or removing the Cycles modifier requires an update to handles */
1083   if (curve && BKE_fcurve_is_cyclic(curve) != was_cyclic)
1084     calchandles_fcurve(curve);
1085
1086   /* did we succeed? */
1087   return ok;
1088 }
1089
1090 /* ********************************************** */