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