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