2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2009 Blender Foundation.
19 * All rights reserved.
22 * Contributor(s): Blender Foundation, Joshua Leung
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/editors/animation/fmodifier_ui.c
28 * \ingroup edanimation
32 /* User-Interface Stuff for F-Modifiers:
33 * This file defines the (C-Coded) templates + editing callbacks needed
34 * by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor,
35 * and NLA-Strips in the NLA Editor.
37 * Copy/Paste Buffer for F-Modifiers:
38 * For now, this is also defined in this file so that it can be shared between the
43 #include "DNA_anim_types.h"
44 #include "DNA_scene_types.h"
46 #include "MEM_guardedalloc.h"
48 #include "BLT_translation.h"
50 #include "BLI_blenlib.h"
51 #include "BLI_utildefines.h"
53 #include "BKE_context.h"
54 #include "BKE_fcurve.h"
59 #include "RNA_access.h"
61 #include "UI_interface.h"
62 #include "UI_resources.h"
64 #include "ED_anim_api.h"
67 /* ********************************************** */
70 // XXX! --------------------------------
71 /* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */
72 #define UI_FLT_MAX 10000.0f
75 #define B_FMODIFIER_REDRAW 20
77 /* callback to verify modifier data */
78 static void validate_fmodifier_cb(bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg))
80 FModifier *fcm = (FModifier *)fcm_v;
81 const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
83 /* call the verify callback on the modifier if applicable */
84 if (fmi && fmi->verify_data)
85 fmi->verify_data(fcm);
88 /* callback to remove the given modifier */
89 static void delete_fmodifier_cb(bContext *C, void *fmods_v, void *fcm_v)
91 ListBase *modifiers = (ListBase *)fmods_v;
92 FModifier *fcm = (FModifier *)fcm_v;
94 /* remove the given F-Modifier from the active modifier-stack */
95 remove_fmodifier(modifiers, fcm);
97 ED_undo_push(C, "Delete F-Curve Modifier");
100 // XXX for now, this is the only way to get updates in all the right places... but would be nice to have a special one in this case
101 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
104 /* --------------- */
106 /* draw settings for generator modifier */
107 static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, short width)
109 FMod_Generator *data = (FMod_Generator *)fcm->data;
110 uiLayout /* *col, */ /* UNUSED */ *row;
114 short bwidth = width - 1.5 * UI_UNIT_X; /* max button width */
116 /* init the RNA-pointer */
117 RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
119 /* basic settings (backdrop + mode selector + some padding) */
120 /* col = uiLayoutColumn(layout, true); */ /* UNUSED */
121 block = uiLayoutGetBlock(layout);
122 UI_block_align_begin(block);
123 but = uiDefButR(block, UI_BTYPE_MENU, B_FMODIFIER_REDRAW, NULL, 0, 0, bwidth, UI_UNIT_Y, &ptr, "mode", -1, 0, 0, -1, -1, NULL);
124 UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
126 uiDefButR(block, UI_BTYPE_TOGGLE, B_FMODIFIER_REDRAW, NULL, 0, 0, bwidth, UI_UNIT_Y, &ptr, "use_additive", -1, 0, 0, -1, -1, NULL);
127 UI_block_align_end(block);
129 /* now add settings for individual modes */
130 switch (data->mode) {
131 case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
133 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
139 /* draw polynomial order selector */
140 row = uiLayoutRow(layout, false);
141 block = uiLayoutGetBlock(row);
142 but = uiDefButI(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Poly Order:"), 0.5f * UI_UNIT_X, 0, bwidth, UI_UNIT_Y,
143 &data->poly_order, 1, 100, 0, 0,
144 TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
145 UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
148 /* calculate maximum width of label for "x^n" labels */
149 if (data->arraysize > 2) {
150 BLI_snprintf(xval, sizeof(xval), "x^%u", data->arraysize);
151 /* XXX: UI_fontstyle_string_width is not accurate */
152 maxXWidth = UI_fontstyle_string_width(fstyle, xval) + 0.5 * UI_UNIT_X;
155 /* basic size (just "x") */
156 maxXWidth = UI_fontstyle_string_width(fstyle, "x") + 0.5 * UI_UNIT_X;
159 /* draw controls for each coefficient and a + sign at end of row */
160 row = uiLayoutRow(layout, true);
161 block = uiLayoutGetBlock(row);
163 cp = data->coefficients;
164 for (i = 0; (i < data->arraysize) && (cp); i++, cp++) {
165 /* To align with first line... */
167 uiDefBut(block, UI_BTYPE_LABEL, 1, " ", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
169 uiDefBut(block, UI_BTYPE_LABEL, 1, "y =", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
172 uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, bwidth / 2, UI_UNIT_Y, cp, -UI_FLT_MAX, UI_FLT_MAX,
173 10, 3, TIP_("Coefficient for polynomial"));
175 /* 'x' param (and '+' if necessary) */
177 BLI_strncpy(xval, "", sizeof(xval));
179 BLI_strncpy(xval, "x", sizeof(xval));
181 BLI_snprintf(xval, sizeof(xval), "x^%u", i);
182 uiDefBut(block, UI_BTYPE_LABEL, 1, xval, 0, 0, maxXWidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, TIP_("Power of x"));
184 if ( (i != (data->arraysize - 1)) || ((i == 0) && data->arraysize == 2) ) {
185 uiDefBut(block, UI_BTYPE_LABEL, 1, "+", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
187 /* next coefficient on a new row */
188 row = uiLayoutRow(layout, true);
189 block = uiLayoutGetBlock(row);
192 /* For alignment in UI! */
193 uiDefBut(block, UI_BTYPE_LABEL, 1, " ", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
199 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial expression */
204 /* draw polynomial order selector */
205 row = uiLayoutRow(layout, false);
206 block = uiLayoutGetBlock(row);
207 but = uiDefButI(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Poly Order:"), 0, 0, width - 1.5 * UI_UNIT_X, UI_UNIT_Y,
208 &data->poly_order, 1, 100, 0, 0,
209 TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
210 UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
213 /* draw controls for each pair of coefficients */
214 row = uiLayoutRow(layout, true);
215 block = uiLayoutGetBlock(row);
217 cp = data->coefficients;
218 for (i = 0; (i < data->poly_order) && (cp); i++, cp += 2) {
219 /* To align with first line */
221 uiDefBut(block, UI_BTYPE_LABEL, 1, " ", 0, 0, 2.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
223 uiDefBut(block, UI_BTYPE_LABEL, 1, "y =", 0, 0, 2.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
224 /* opening bracket */
225 uiDefBut(block, UI_BTYPE_LABEL, 1, "(", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
228 uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, cp, -UI_FLT_MAX, UI_FLT_MAX,
229 10, 3, TIP_("Coefficient of x"));
231 uiDefBut(block, UI_BTYPE_LABEL, 1, "x +", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
233 uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, cp + 1, -UI_FLT_MAX, UI_FLT_MAX,
234 10, 3, TIP_("Second coefficient"));
236 /* closing bracket and multiplication sign */
237 if ( (i != (data->poly_order - 1)) || ((i == 0) && data->poly_order == 2) ) {
238 uiDefBut(block, UI_BTYPE_LABEL, 1, ") \xc3\x97", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
240 /* set up new row for the next pair of coefficients */
241 row = uiLayoutRow(layout, true);
242 block = uiLayoutGetBlock(row);
245 uiDefBut(block, UI_BTYPE_LABEL, 1, ") ", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
252 /* --------------- */
254 /* draw settings for generator modifier */
255 static void draw_modifier__fn_generator(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
260 /* init the RNA-pointer */
261 RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
263 /* add the settings */
264 col = uiLayoutColumn(layout, true);
265 uiItemR(col, &ptr, "function_type", 0, "", ICON_NONE);
266 uiItemR(col, &ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
268 col = uiLayoutColumn(layout, false); // no grouping for now
269 uiItemR(col, &ptr, "amplitude", 0, NULL, ICON_NONE);
270 uiItemR(col, &ptr, "phase_multiplier", 0, NULL, ICON_NONE);
271 uiItemR(col, &ptr, "phase_offset", 0, NULL, ICON_NONE);
272 uiItemR(col, &ptr, "value_offset", 0, NULL, ICON_NONE);
275 /* --------------- */
277 /* draw settings for cycles modifier */
278 static void draw_modifier__cycles(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
280 uiLayout *split, *col;
283 /* init the RNA-pointer */
284 RNA_pointer_create(id, &RNA_FModifierCycles, fcm, &ptr);
286 /* split into 2 columns
287 * NOTE: the mode comboboxes shouldn't get labels, otherwise there isn't enough room
289 split = uiLayoutSplit(layout, 0.5f, false);
292 col = uiLayoutColumn(split, true);
293 uiItemL(col, IFACE_("Before:"), ICON_NONE);
294 uiItemR(col, &ptr, "mode_before", 0, "", ICON_NONE);
295 uiItemR(col, &ptr, "cycles_before", 0, NULL, ICON_NONE);
298 col = uiLayoutColumn(split, true);
299 uiItemL(col, IFACE_("After:"), ICON_NONE);
300 uiItemR(col, &ptr, "mode_after", 0, "", ICON_NONE);
301 uiItemR(col, &ptr, "cycles_after", 0, NULL, ICON_NONE);
304 /* --------------- */
306 /* draw settings for noise modifier */
307 static void draw_modifier__noise(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
309 uiLayout *split, *col;
312 /* init the RNA-pointer */
313 RNA_pointer_create(id, &RNA_FModifierNoise, fcm, &ptr);
316 uiItemR(layout, &ptr, "blend_type", 0, NULL, ICON_NONE);
318 /* split into 2 columns */
319 split = uiLayoutSplit(layout, 0.5f, false);
322 col = uiLayoutColumn(split, false);
323 uiItemR(col, &ptr, "scale", 0, NULL, ICON_NONE);
324 uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE);
325 uiItemR(col, &ptr, "offset", 0, NULL, ICON_NONE);
328 col = uiLayoutColumn(split, false);
329 uiItemR(col, &ptr, "phase", 0, NULL, ICON_NONE);
330 uiItemR(col, &ptr, "depth", 0, NULL, ICON_NONE);
333 /* callback to add new envelope data point */
334 static void fmod_envelope_addpoint_cb(bContext *C, void *fcm_dv, void *UNUSED(arg))
336 Scene *scene = CTX_data_scene(C);
337 FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
338 FCM_EnvelopeData *fedn;
339 FCM_EnvelopeData fed;
341 /* init template data */
344 fed.time = (float)scene->r.cfra; // XXX make this int for ease of use?
347 /* check that no data exists for the current frame... */
350 int i = BKE_fcm_envelope_find_index(env->data, (float)(scene->r.cfra), env->totvert, &exists);
352 /* binarysearch_...() will set exists by default to 0, so if it is non-zero, that means that the point exists already */
357 fedn = MEM_callocN((env->totvert + 1) * sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
359 /* add the points that should occur before the point to be pasted */
361 memcpy(fedn, env->data, i * sizeof(FCM_EnvelopeData));
363 /* add point to paste at index i */
366 /* add the points that occur after the point to be pasted */
367 if (i < env->totvert)
368 memcpy(fedn + i + 1, env->data + i, (env->totvert - i) * sizeof(FCM_EnvelopeData));
370 /* replace (+ free) old with new */
371 MEM_freeN(env->data);
377 env->data = MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
384 /* callback to remove envelope data point */
385 // TODO: should we have a separate file for things like this?
386 static void fmod_envelope_deletepoint_cb(bContext *UNUSED(C), void *fcm_dv, void *ind_v)
388 FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
389 FCM_EnvelopeData *fedn;
390 int index = GET_INT_FROM_POINTER(ind_v);
392 /* check that no data exists for the current frame... */
393 if (env->totvert > 1) {
394 /* allocate a new smaller array */
395 fedn = MEM_callocN(sizeof(FCM_EnvelopeData) * (env->totvert - 1), "FCM_EnvelopeData");
397 memcpy(fedn, env->data, sizeof(FCM_EnvelopeData) * (index));
398 memcpy(fedn + index, env->data + (index + 1), sizeof(FCM_EnvelopeData) * ((env->totvert - index) - 1));
400 /* free old array, and set the new */
401 MEM_freeN(env->data);
406 /* just free array, since the only vert was deleted */
408 MEM_freeN(env->data);
415 /* draw settings for envelope modifier */
416 static void draw_modifier__envelope(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
418 FMod_Envelope *env = (FMod_Envelope *)fcm->data;
419 FCM_EnvelopeData *fed;
426 /* init the RNA-pointer */
427 RNA_pointer_create(id, &RNA_FModifierEnvelope, fcm, &ptr);
429 /* general settings */
430 col = uiLayoutColumn(layout, true);
431 uiItemL(col, IFACE_("Envelope:"), ICON_NONE);
432 uiItemR(col, &ptr, "reference_value", 0, NULL, ICON_NONE);
434 row = uiLayoutRow(col, true);
435 uiItemR(row, &ptr, "default_min", 0, IFACE_("Min"), ICON_NONE);
436 uiItemR(row, &ptr, "default_max", 0, IFACE_("Max"), ICON_NONE);
438 /* control points header */
439 /* TODO: move this control-point control stuff to using the new special widgets for lists
440 * the current way is far too cramped */
441 row = uiLayoutRow(layout, false);
442 block = uiLayoutGetBlock(row);
444 uiDefBut(block, UI_BTYPE_LABEL, 1, IFACE_("Control Points:"), 0, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
446 but = uiDefBut(block, UI_BTYPE_BUT, B_FMODIFIER_REDRAW, IFACE_("Add Point"), 0, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y,
447 NULL, 0, 0, 0, 0, TIP_("Add a new control-point to the envelope on the current frame"));
448 UI_but_func_set(but, fmod_envelope_addpoint_cb, env, NULL);
450 /* control points list */
451 for (i = 0, fed = env->data; i < env->totvert; i++, fed++) {
452 /* get a new row to operate on */
453 row = uiLayoutRow(layout, true);
454 block = uiLayoutGetBlock(row);
456 UI_block_align_begin(block);
457 but = uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Fra:"), 0, 0, 4.5 * UI_UNIT_X, UI_UNIT_Y,
458 &fed->time, -MAXFRAMEF, MAXFRAMEF, 10, 1, TIP_("Frame that envelope point occurs"));
459 UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
461 uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Min:"), 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y,
462 &fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, TIP_("Minimum bound of envelope at this point"));
463 uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Max:"), 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y,
464 &fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, TIP_("Maximum bound of envelope at this point"));
466 but = uiDefIconBut(block, UI_BTYPE_BUT, B_FMODIFIER_REDRAW, ICON_X, 0, 0, 0.9 * UI_UNIT_X, UI_UNIT_Y,
467 NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete envelope control point"));
468 UI_but_func_set(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i));
469 UI_block_align_begin(block);
473 /* --------------- */
475 /* draw settings for limits modifier */
476 static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
478 uiLayout *split, *col /* , *row */ /* UNUSED */;
481 /* init the RNA-pointer */
482 RNA_pointer_create(id, &RNA_FModifierLimits, fcm, &ptr);
486 /* row = uiLayoutRow(layout, false); */ /* UNUSED */
488 /* split into 2 columns */
489 split = uiLayoutSplit(layout, 0.5f, false);
492 col = uiLayoutColumn(split, true);
493 uiItemR(col, &ptr, "use_min_x", 0, NULL, ICON_NONE);
494 uiItemR(col, &ptr, "min_x", 0, NULL, ICON_NONE);
497 col = uiLayoutColumn(split, true);
498 uiItemR(col, &ptr, "use_min_y", 0, NULL, ICON_NONE);
499 uiItemR(col, &ptr, "min_y", 0, NULL, ICON_NONE);
504 /* row = uiLayoutRow(layout, false); */ /* UNUSED */
506 /* split into 2 columns */
507 split = uiLayoutSplit(layout, 0.5f, false);
510 col = uiLayoutColumn(split, true);
511 uiItemR(col, &ptr, "use_max_x", 0, NULL, ICON_NONE);
512 uiItemR(col, &ptr, "max_x", 0, NULL, ICON_NONE);
515 col = uiLayoutColumn(split, true);
516 uiItemR(col, &ptr, "use_max_y", 0, NULL, ICON_NONE);
517 uiItemR(col, &ptr, "max_y", 0, NULL, ICON_NONE);
521 /* --------------- */
523 /* draw settings for stepped interpolation modifier */
524 static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
529 /* init the RNA-pointer */
530 RNA_pointer_create(id, &RNA_FModifierStepped, fcm, &ptr);
532 /* block 1: "stepping" settings */
533 col = uiLayoutColumn(layout, false);
534 uiItemR(col, &ptr, "frame_step", 0, NULL, ICON_NONE);
535 uiItemR(col, &ptr, "frame_offset", 0, NULL, ICON_NONE);
537 /* block 2: start range settings */
538 col = uiLayoutColumn(layout, true);
539 uiItemR(col, &ptr, "use_frame_start", 0, NULL, ICON_NONE);
541 sub = uiLayoutColumn(col, true);
542 uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_start"));
543 uiItemR(sub, &ptr, "frame_start", 0, NULL, ICON_NONE);
545 /* block 3: end range settings */
546 col = uiLayoutColumn(layout, true);
547 uiItemR(col, &ptr, "use_frame_end", 0, NULL, ICON_NONE);
549 sub = uiLayoutColumn(col, true);
550 uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_end"));
551 uiItemR(sub, &ptr, "frame_end", 0, NULL, ICON_NONE);
554 /* --------------- */
556 void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
558 const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
559 uiLayout *box, *row, *sub, *col;
565 /* init the RNA-pointer */
566 RNA_pointer_create(id, &RNA_FModifier, fcm, &ptr);
570 /* get layout-row + UI-block for this */
571 box = uiLayoutBox(layout);
573 row = uiLayoutRow(box, false);
574 block = uiLayoutGetBlock(row); // err...
576 /* left-align -------------------------------------------- */
577 sub = uiLayoutRow(row, true);
578 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
580 UI_block_emboss_set(block, UI_EMBOSS_NONE);
583 uiItemR(sub, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
585 /* checkbox for 'active' status (for now) */
586 uiItemR(sub, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
590 uiItemL(sub, IFACE_(fmi->name), ICON_NONE);
592 uiItemL(sub, IFACE_("<Unknown Modifier>"), ICON_NONE);
594 /* right-align ------------------------------------------- */
595 sub = uiLayoutRow(row, true);
596 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
600 uiItemR(sub, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
602 UI_block_emboss_set(block, UI_EMBOSS_NONE);
605 but = uiDefIconBut(block, UI_BTYPE_BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y,
606 NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete F-Curve Modifier"));
607 UI_but_func_set(but, delete_fmodifier_cb, modifiers, fcm);
609 UI_block_emboss_set(block, UI_EMBOSS);
612 /* when modifier is expanded, draw settings */
613 if (fcm->flag & FMODIFIER_FLAG_EXPANDED) {
614 /* set up the flexible-box layout which acts as the backdrop for the modifier settings */
615 box = uiLayoutBox(layout);
617 /* draw settings for individual modifiers */
619 case FMODIFIER_TYPE_GENERATOR: /* Generator */
620 draw_modifier__generator(box, id, fcm, width);
623 case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */
624 draw_modifier__fn_generator(box, id, fcm, width);
627 case FMODIFIER_TYPE_CYCLES: /* Cycles */
628 draw_modifier__cycles(box, id, fcm, width);
631 case FMODIFIER_TYPE_ENVELOPE: /* Envelope */
632 draw_modifier__envelope(box, id, fcm, width);
635 case FMODIFIER_TYPE_LIMITS: /* Limits */
636 draw_modifier__limits(box, id, fcm, width);
639 case FMODIFIER_TYPE_NOISE: /* Noise */
640 draw_modifier__noise(box, id, fcm, width);
643 case FMODIFIER_TYPE_STEPPED: /* Stepped */
644 draw_modifier__stepped(box, id, fcm, width);
647 default: /* unknown type */
651 /* one last panel below this: FModifier range */
652 // TODO: experiment with placement of this
654 box = uiLayoutBox(layout);
656 /* restricted range ----------------------------------------------------- */
657 col = uiLayoutColumn(box, true);
659 /* top row: use restricted range */
660 row = uiLayoutRow(col, true);
661 uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE);
663 if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
664 /* second row: settings */
665 row = uiLayoutRow(col, true);
667 uiItemR(row, &ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE);
668 uiItemR(row, &ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
670 /* third row: blending influence */
671 row = uiLayoutRow(col, true);
673 uiItemR(row, &ptr, "blend_in", 0, IFACE_("In"), ICON_NONE);
674 uiItemR(row, &ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE);
677 /* influence -------------------------------------------------------------- */
678 col = uiLayoutColumn(box, true);
680 /* top row: use influence */
681 uiItemR(col, &ptr, "use_influence", 0, NULL, ICON_NONE);
683 if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE) {
684 /* second row: influence value */
685 uiItemR(col, &ptr, "influence", 0, NULL, ICON_NONE);
691 /* ********************************************** */
692 /* COPY/PASTE BUFFER STUFF */
694 /* Copy/Paste Buffer itself (list of FModifier 's) */
695 static ListBase fmodifier_copypaste_buf = {NULL, NULL};
699 /* free the copy/paste buffer */
700 void ANIM_fmodifiers_copybuf_free(void)
702 /* just free the whole buffer */
703 free_fmodifiers(&fmodifier_copypaste_buf);
706 /* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
707 * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
708 * - active: only copy the active modifier
710 bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
715 if (ELEM(NULL, modifiers, modifiers->first))
718 /* copy the whole list, or just the active one? */
720 FModifier *fcm = find_active_fmodifier(modifiers);
723 FModifier *fcmN = copy_fmodifier(fcm);
724 BLI_addtail(&fmodifier_copypaste_buf, fcmN);
730 copy_fmodifiers(&fmodifier_copypaste_buf, modifiers);
732 /* did we succeed? */
736 /* 'Paste' the F-Modifier(s) from the buffer to the specified list
737 * - replace: free all the existing modifiers to leave only the pasted ones
739 bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace)
745 if (modifiers == NULL)
748 /* if replacing the list, free the existing modifiers */
750 free_fmodifiers(modifiers);
752 /* now copy over all the modifiers in the buffer to the end of the list */
753 for (fcm = fmodifier_copypaste_buf.first; fcm; fcm = fcm->next) {
754 /* make a copy of it */
755 FModifier *fcmN = copy_fmodifier(fcm);
757 /* make sure the new one isn't active, otherwise the list may get several actives */
758 fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE;
760 /* now add it to the end of the list */
761 BLI_addtail(modifiers, fcmN);
765 /* did we succeed? */
769 /* ********************************************** */