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