Blender V4.3
fmodifier_ui.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
16#include <cstring>
17
18#include "DNA_anim_types.h"
19#include "DNA_scene_types.h"
20#include "DNA_space_types.h"
21
22#include "MEM_guardedalloc.h"
23
24#include "BLT_translation.hh"
25
26#include "BLI_blenlib.h"
27#include "BLI_utildefines.h"
28
29#include "BKE_context.hh"
30#include "BKE_fcurve.hh"
31#include "BKE_screen.hh"
32
33#include "WM_api.hh"
34#include "WM_types.hh"
35
36#include "RNA_access.hh"
37#include "RNA_prototypes.hh"
38
39#include "UI_interface.hh"
40#include "UI_resources.hh"
41
42#include "ED_anim_api.hh"
43#include "ED_undo.hh"
44
45#include "DEG_depsgraph.hh"
46
47using PanelDrawFn = void (*)(const bContext *, Panel *);
48static void fmodifier_panel_header(const bContext *C, Panel *panel);
49
50/* -------------------------------------------------------------------- */
58{
59 ScrArea *area = CTX_wm_area(C);
60
61 if (area->spacetype == SPACE_GRAPH) {
63 return &fcu->modifiers;
64 }
65
66 if (area->spacetype == SPACE_NLA) {
68 return &strip->modifiers;
69 }
70
71 /* This should not be called in any other space. */
72 BLI_assert(false);
73 return nullptr;
74}
75
80static PointerRNA *fmodifier_get_pointers(const bContext *C, const Panel *panel, ID **r_owner_id)
81{
83
84 if (r_owner_id != nullptr) {
85 *r_owner_id = ptr->owner_id;
86 }
87
88 if (C != nullptr && CTX_wm_space_graph(C)) {
89 const FCurve *fcu = ANIM_graph_context_fcurve(C);
91 }
92
93 return ptr;
94}
95
99static void fmodifier_reorder(bContext *C, Panel *panel, int new_index)
100{
101 ID *owner_id;
102 PointerRNA *ptr = fmodifier_get_pointers(nullptr, panel, &owner_id);
103 FModifier *fcm = static_cast<FModifier *>(ptr->data);
105
106 /* Cycles modifier has to be the first, so make sure it's kept that way. */
108 WM_report(RPT_ERROR, "Modifier requires original data");
109 return;
110 }
111
113
114 /* Again, make sure we don't move a modifier before a cycles modifier. */
115 FModifier *fcm_first = static_cast<FModifier *>(modifiers->first);
116 const FModifierTypeInfo *fmi_first = get_fmodifier_typeinfo(fcm_first->type);
117 if (fmi_first->requires_flag & FMI_REQUIRES_ORIGINAL_DATA && new_index == 0) {
118 WM_report(RPT_ERROR, "Modifier requires original data");
119 return;
120 }
121
122 int current_index = BLI_findindex(modifiers, fcm);
123 BLI_assert(current_index >= 0);
124 BLI_assert(new_index >= 0);
125
126 /* Don't do anything if the drag didn't change the index. */
127 if (current_index == new_index) {
128 return;
129 }
130
131 /* Move the FModifier in the list. */
132 BLI_listbase_link_move(modifiers, fcm, new_index - current_index);
133
134 ED_undo_push(C, "Reorder F-Curve Modifier");
135
138}
139
140static short get_fmodifier_expand_flag(const bContext * /*C*/, Panel *panel)
141{
142 PointerRNA *ptr = fmodifier_get_pointers(nullptr, panel, nullptr);
143 FModifier *fcm = (FModifier *)ptr->data;
144
145 return fcm->ui_expand_flag;
146}
147
148static void set_fmodifier_expand_flag(const bContext * /*C*/, Panel *panel, short expand_flag)
149{
150 PointerRNA *ptr = fmodifier_get_pointers(nullptr, panel, nullptr);
151 FModifier *fcm = (FModifier *)ptr->data;
152
153 fcm->ui_expand_flag = expand_flag;
154}
155
157 eFModifier_Types type,
158 PanelDrawFn draw,
159 PanelTypePollFn poll,
160 const char *id_prefix)
161{
162 PanelType *panel_type = static_cast<PanelType *>(MEM_callocN(sizeof(PanelType), __func__));
163
164 /* Intentionally leave the label field blank. The header is filled with buttons. */
165 const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
166 SNPRINTF(panel_type->idname, "%s_PT_%s", id_prefix, fmi->name);
167 STRNCPY(panel_type->category, "Modifiers");
169
171 panel_type->draw = draw;
172 panel_type->poll = poll;
173
174 /* Give the panel the special flag that says it was built here and corresponds to a
175 * modifier rather than a #PanelType. */
177 panel_type->reorder = fmodifier_reorder;
180
181 BLI_addtail(&region_type->paneltypes, panel_type);
182
183 return panel_type;
184}
185
193 const char *name,
194 const char *label,
195 PanelDrawFn draw_header,
196 PanelDrawFn draw,
197 PanelTypePollFn poll,
198 PanelType *parent)
199{
200 PanelType *panel_type = static_cast<PanelType *>(MEM_callocN(sizeof(PanelType), __func__));
201
202 BLI_assert(parent != nullptr);
203 SNPRINTF(panel_type->idname, "%s_%s", parent->idname, name);
204 STRNCPY(panel_type->label, label);
205 STRNCPY(panel_type->category, "Modifiers");
207
208 panel_type->draw_header = draw_header;
209 panel_type->draw = draw;
210 panel_type->poll = poll;
211 panel_type->flag = PANEL_TYPE_DEFAULT_CLOSED;
212
213 STRNCPY(panel_type->parent_id, parent->idname);
214 panel_type->parent = parent;
215 BLI_addtail(&parent->children, BLI_genericNodeN(panel_type));
216 BLI_addtail(&region_type->paneltypes, panel_type);
217
218 return panel_type;
219}
220
223/* -------------------------------------------------------------------- */
227#define B_REDR 1
228#define B_FMODIFIER_REDRAW 20
229
230/* Callback to remove the given modifier. */
235
236static void delete_fmodifier_cb(bContext *C, void *ctx_v, void *fcm_v)
237{
239 ListBase *modifiers = ctx->modifiers;
240 FModifier *fcm = (FModifier *)fcm_v;
241
242 /* remove the given F-Modifier from the active modifier-stack */
243 remove_fmodifier(modifiers, fcm);
244
245 ED_undo_push(C, "Delete F-Curve Modifier");
246
249}
250
252{
253 FModifier *fcm = (FModifier *)ptr->data;
254 uiItemS(layout);
255
256 uiLayout *row = uiLayoutRowWithHeading(layout, true, IFACE_("Influence"));
257 uiItemR(row, ptr, "use_influence", UI_ITEM_NONE, "", ICON_NONE);
258 uiLayout *sub = uiLayoutRow(row, true);
259
261 uiItemR(sub, ptr, "influence", UI_ITEM_NONE, "", ICON_NONE);
262}
263
265{
266 uiLayout *layout = panel->layout;
267
268 PointerRNA *ptr = fmodifier_get_pointers(C, panel, nullptr);
269
270 uiItemR(layout, ptr, "use_restricted_range", UI_ITEM_NONE, nullptr, ICON_NONE);
271}
272
273static void fmodifier_frame_range_draw(const bContext *C, Panel *panel)
274{
275 uiLayout *col;
276 uiLayout *layout = panel->layout;
277
278 PointerRNA *ptr = fmodifier_get_pointers(C, panel, nullptr);
279
280 uiLayoutSetPropSep(layout, true);
281 uiLayoutSetPropDecorate(layout, false);
282
283 FModifier *fcm = (FModifier *)ptr->data;
285
286 col = uiLayoutColumn(layout, true);
287 uiItemR(col, ptr, "frame_start", UI_ITEM_NONE, IFACE_("Start"), ICON_NONE);
288 uiItemR(col, ptr, "frame_end", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
289
290 col = uiLayoutColumn(layout, true);
291 uiItemR(col, ptr, "blend_in", UI_ITEM_NONE, IFACE_("Blend In"), ICON_NONE);
292 uiItemR(col, ptr, "blend_out", UI_ITEM_NONE, IFACE_("Out"), ICON_NONE);
293}
294
295static void fmodifier_panel_header(const bContext *C, Panel *panel)
296{
297 uiLayout *layout = panel->layout;
298
299 ID *owner_id;
300 PointerRNA *ptr = fmodifier_get_pointers(C, panel, &owner_id);
301 FModifier *fcm = (FModifier *)ptr->data;
303
304 uiBlock *block = uiLayoutGetBlock(layout);
305
306 uiLayout *sub = uiLayoutRow(layout, true);
307
308 /* Checkbox for 'active' status (for now). */
309 uiItemR(sub, ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
310
311 /* Name. */
312 if (fmi) {
313 uiItemR(sub, ptr, "name", UI_ITEM_NONE, "", ICON_NONE);
314 }
315 else {
316 uiItemL(sub, IFACE_("<Unknown Modifier>"), ICON_NONE);
317 }
318 /* Right align. */
319 sub = uiLayoutRow(layout, true);
322
323 /* 'Mute' button. */
324 uiItemR(sub, ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
325
326 /* Delete button. */
327 uiBut *but = uiDefIconBut(block,
329 B_REDR,
330 ICON_X,
331 0,
332 0,
333 UI_UNIT_X,
334 UI_UNIT_Y,
335 nullptr,
336 0.0,
337 0.0,
338 TIP_("Delete Modifier"));
340 MEM_mallocN(sizeof(FModifierDeleteContext), __func__));
341 ctx->owner_id = owner_id;
343 BLI_assert(ctx->modifiers != nullptr);
344
346
347 uiItemS(layout);
348}
349
352/* -------------------------------------------------------------------- */
356static void generator_panel_draw(const bContext *C, Panel *panel)
357{
358 uiLayout *layout = panel->layout;
359
360 ID *owner_id;
361 PointerRNA *ptr = fmodifier_get_pointers(C, panel, &owner_id);
362 FModifier *fcm = (FModifier *)ptr->data;
363 FMod_Generator *data = (FMod_Generator *)fcm->data;
364
365 uiItemR(layout, ptr, "mode", UI_ITEM_NONE, "", ICON_NONE);
366
367 uiLayoutSetPropSep(layout, true);
368 uiLayoutSetPropDecorate(layout, false);
369
370 uiItemR(layout, ptr, "use_additive", UI_ITEM_NONE, nullptr, ICON_NONE);
371
372 uiItemR(layout, ptr, "poly_order", UI_ITEM_NONE, IFACE_("Order"), ICON_NONE);
373
374 PropertyRNA *prop = RNA_struct_find_property(ptr, "coefficients");
375 uiLayout *col = uiLayoutColumn(layout, true);
376 switch (data->mode) {
377 case FCM_GENERATOR_POLYNOMIAL: /* Polynomial expression. */
378 {
379
380 char xval[32];
381
382 /* The first value gets a "Coefficient" label. */
383 STRNCPY(xval, N_("Coefficient"));
384
385 for (int i = 0; i < data->arraysize; i++) {
386 uiItemFullR(col, ptr, prop, i, 0, UI_ITEM_NONE, IFACE_(xval), ICON_NONE);
387 SNPRINTF(xval, "x^%d", i + 1);
388 }
389 break;
390 }
391 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial expression */
392 {
393 {
394 /* Add column labels above the buttons to prevent confusion.
395 * Fake the property split layout, otherwise the labels use the full row. */
396 uiLayout *split = uiLayoutSplit(col, 0.4f, false);
397 uiLayoutColumn(split, false);
398 uiLayout *title_col = uiLayoutColumn(split, false);
399 uiLayout *title_row = uiLayoutRow(title_col, true);
400 uiItemL(title_row, CTX_IFACE_(BLT_I18NCONTEXT_ID_ACTION, "A"), ICON_NONE);
401 uiItemL(title_row, CTX_IFACE_(BLT_I18NCONTEXT_ID_ACTION, "B"), ICON_NONE);
402 }
403
404 uiLayout *first_row = uiLayoutRow(col, true);
405 uiItemFullR(first_row, ptr, prop, 0, 0, UI_ITEM_NONE, IFACE_("y = (Ax + B)"), ICON_NONE);
406 uiItemFullR(first_row, ptr, prop, 1, 0, UI_ITEM_NONE, "", ICON_NONE);
407 for (int i = 2; i < data->arraysize - 1; i += 2) {
408 /* \u00d7 is the multiplication symbol. */
409 uiLayout *row = uiLayoutRow(col, true);
410 uiItemFullR(row, ptr, prop, i, 0, UI_ITEM_NONE, IFACE_("\u00d7 (Ax + B)"), ICON_NONE);
411 uiItemFullR(row, ptr, prop, i + 1, 0, UI_ITEM_NONE, "", ICON_NONE);
412 }
413 break;
414 }
415 }
416
418}
419
420static void panel_register_generator(ARegionType *region_type,
421 const char *id_prefix,
422 PanelTypePollFn poll_fn)
423{
425 region_type, FMODIFIER_TYPE_GENERATOR, generator_panel_draw, poll_fn, id_prefix);
426 fmodifier_subpanel_register(region_type,
427 "frame_range",
428 "",
431 poll_fn,
432 panel_type);
433}
434
437/* -------------------------------------------------------------------- */
441static void fn_generator_panel_draw(const bContext *C, Panel *panel)
442{
443 uiLayout *col;
444 uiLayout *layout = panel->layout;
445
446 PointerRNA *ptr = fmodifier_get_pointers(C, panel, nullptr);
447
448 uiItemR(layout, ptr, "function_type", UI_ITEM_NONE, "", ICON_NONE);
449
450 uiLayoutSetPropSep(layout, true);
451 uiLayoutSetPropDecorate(layout, false);
452
453 col = uiLayoutColumn(layout, false);
454 uiItemR(col, ptr, "use_additive", UI_ITEM_NONE, nullptr, ICON_NONE);
455
456 col = uiLayoutColumn(layout, false);
457 uiItemR(col, ptr, "amplitude", UI_ITEM_NONE, nullptr, ICON_NONE);
458 uiItemR(col, ptr, "phase_multiplier", UI_ITEM_NONE, nullptr, ICON_NONE);
459 uiItemR(col, ptr, "phase_offset", UI_ITEM_NONE, nullptr, ICON_NONE);
460 uiItemR(col, ptr, "value_offset", UI_ITEM_NONE, nullptr, ICON_NONE);
461
463}
464
466 const char *id_prefix,
467 PanelTypePollFn poll_fn)
468{
470 region_type, FMODIFIER_TYPE_FN_GENERATOR, fn_generator_panel_draw, poll_fn, id_prefix);
471 fmodifier_subpanel_register(region_type,
472 "frame_range",
473 "",
476 poll_fn,
477 panel_type);
478}
479
482/* -------------------------------------------------------------------- */
486static void cycles_panel_draw(const bContext *C, Panel *panel)
487{
488 uiLayout *col;
489 uiLayout *layout = panel->layout;
490
491 PointerRNA *ptr = fmodifier_get_pointers(C, panel, nullptr);
492
493 uiLayoutSetPropSep(layout, true);
494 uiLayoutSetPropDecorate(layout, false);
495
496 /* Before. */
497 col = uiLayoutColumn(layout, false);
498 uiItemR(col, ptr, "mode_before", UI_ITEM_NONE, nullptr, ICON_NONE);
499 uiItemR(col, ptr, "cycles_before", UI_ITEM_NONE, IFACE_("Count"), ICON_NONE);
500
501 /* After. */
502 col = uiLayoutColumn(layout, false);
503 uiItemR(col, ptr, "mode_after", UI_ITEM_NONE, nullptr, ICON_NONE);
504 uiItemR(col, ptr, "cycles_after", UI_ITEM_NONE, IFACE_("Count"), ICON_NONE);
505
507}
508
509static void panel_register_cycles(ARegionType *region_type,
510 const char *id_prefix,
511 PanelTypePollFn poll_fn)
512{
514 region_type, FMODIFIER_TYPE_CYCLES, cycles_panel_draw, poll_fn, id_prefix);
515 fmodifier_subpanel_register(region_type,
516 "frame_range",
517 "",
520 poll_fn,
521 panel_type);
522}
523
526/* -------------------------------------------------------------------- */
530static void noise_panel_draw(const bContext *C, Panel *panel)
531{
532 uiLayout *col;
533 uiLayout *layout = panel->layout;
534
535 PointerRNA *ptr = fmodifier_get_pointers(C, panel, nullptr);
536
537 uiLayoutSetPropSep(layout, true);
538 uiLayoutSetPropDecorate(layout, false);
539
540 uiItemR(layout, ptr, "blend_type", UI_ITEM_NONE, nullptr, ICON_NONE);
541
542 col = uiLayoutColumn(layout, false);
543 uiItemR(col, ptr, "scale", UI_ITEM_NONE, nullptr, ICON_NONE);
544 uiItemR(col, ptr, "strength", UI_ITEM_NONE, nullptr, ICON_NONE);
545 uiItemR(col, ptr, "offset", UI_ITEM_NONE, nullptr, ICON_NONE);
546 uiItemR(col, ptr, "phase", UI_ITEM_NONE, nullptr, ICON_NONE);
547 uiItemR(col, ptr, "depth", UI_ITEM_NONE, nullptr, ICON_NONE);
548
550}
551
552static void panel_register_noise(ARegionType *region_type,
553 const char *id_prefix,
554 PanelTypePollFn poll_fn)
555{
557 region_type, FMODIFIER_TYPE_NOISE, noise_panel_draw, poll_fn, id_prefix);
558 fmodifier_subpanel_register(region_type,
559 "frame_range",
560 "",
563 poll_fn,
564 panel_type);
565}
566
569/* -------------------------------------------------------------------- */
573static void fmod_envelope_addpoint_cb(bContext *C, void *fcm_dv, void * /*arg*/)
574{
575 Scene *scene = CTX_data_scene(C);
576 FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
577 FCM_EnvelopeData *fedn;
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 = static_cast<FCM_EnvelopeData *>(
599 MEM_callocN((env->totvert + 1) * sizeof(FCM_EnvelopeData), "FCM_EnvelopeData"));
600
601 /* add the points that should occur before the point to be pasted */
602 if (i > 0) {
603 memcpy(fedn, env->data, i * sizeof(FCM_EnvelopeData));
604 }
605
606 /* add point to paste at index i */
607 *(fedn + i) = fed;
608
609 /* add the points that occur after the point to be pasted */
610 if (i < env->totvert) {
611 memcpy(fedn + i + 1, env->data + i, (env->totvert - i) * sizeof(FCM_EnvelopeData));
612 }
613
614 /* replace (+ free) old with new */
615 MEM_freeN(env->data);
616 env->data = fedn;
617
618 env->totvert++;
619 }
620 else {
621 env->data = static_cast<FCM_EnvelopeData *>(
622 MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData"));
623 *(env->data) = fed;
624
625 env->totvert = 1;
626 }
627}
628
629/* callback to remove envelope data point */
630/* TODO: should we have a separate file for things like this? */
631static void fmod_envelope_deletepoint_cb(bContext * /*C*/, void *fcm_dv, void *ind_v)
632{
633 FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
634 FCM_EnvelopeData *fedn;
635 int index = POINTER_AS_INT(ind_v);
636
637 /* check that no data exists for the current frame... */
638 if (env->totvert > 1) {
639 /* allocate a new smaller array */
640 fedn = static_cast<FCM_EnvelopeData *>(
641 MEM_callocN(sizeof(FCM_EnvelopeData) * (env->totvert - 1), "FCM_EnvelopeData"));
642
643 memcpy(fedn, env->data, sizeof(FCM_EnvelopeData) * (index));
644 memcpy(fedn + index,
645 env->data + (index + 1),
646 sizeof(FCM_EnvelopeData) * ((env->totvert - index) - 1));
647
648 /* free old array, and set the new */
649 MEM_freeN(env->data);
650 env->data = fedn;
651 env->totvert--;
652 }
653 else {
654 /* just free array, since the only vert was deleted */
655 MEM_SAFE_FREE(env->data);
656 env->totvert = 0;
657 }
658}
659
660/* draw settings for envelope modifier */
661static void envelope_panel_draw(const bContext *C, Panel *panel)
662{
663 uiLayout *row, *col;
664 uiLayout *layout = panel->layout;
665
666 ID *owner_id;
667 PointerRNA *ptr = fmodifier_get_pointers(C, panel, &owner_id);
668 FModifier *fcm = (FModifier *)ptr->data;
669 FMod_Envelope *env = (FMod_Envelope *)fcm->data;
670
671 uiLayoutSetPropSep(layout, true);
672 uiLayoutSetPropDecorate(layout, false);
673
674 /* General settings. */
675 col = uiLayoutColumn(layout, true);
676 uiItemR(col, ptr, "reference_value", UI_ITEM_NONE, IFACE_("Reference"), ICON_NONE);
677 uiItemR(col, ptr, "default_min", UI_ITEM_NONE, IFACE_("Min"), ICON_NONE);
678 uiItemR(col, ptr, "default_max", UI_ITEM_NONE, IFACE_("Max"), ICON_NONE);
679
680 /* Control points list. */
681
682 row = uiLayoutRow(layout, false);
683 uiBlock *block = uiLayoutGetBlock(row);
684
685 uiBut *but = uiDefBut(block,
688 IFACE_("Add Control Point"),
689 0,
690 0,
691 7.5 * UI_UNIT_X,
692 UI_UNIT_Y,
693 nullptr,
694 0,
695 0,
696 TIP_("Add a new control-point to the envelope on the current frame"));
697 UI_but_func_set(but, fmod_envelope_addpoint_cb, env, nullptr);
698
699 col = uiLayoutColumn(layout, false);
700 uiLayoutSetPropSep(col, false);
701
702 FCM_EnvelopeData *fed = env->data;
703 for (int i = 0; i < env->totvert; i++, fed++) {
704 PointerRNA ctrl_ptr = RNA_pointer_create(owner_id, &RNA_FModifierEnvelopeControlPoint, fed);
705
706 /* get a new row to operate on */
707 row = uiLayoutRow(col, true);
708 block = uiLayoutGetBlock(row);
709
710 uiItemR(row, &ctrl_ptr, "frame", UI_ITEM_NONE, nullptr, ICON_NONE);
711 uiItemR(row, &ctrl_ptr, "min", UI_ITEM_NONE, IFACE_("Min"), ICON_NONE);
712 uiItemR(row, &ctrl_ptr, "max", UI_ITEM_NONE, IFACE_("Max"), ICON_NONE);
713
714 but = uiDefIconBut(block,
717 ICON_X,
718 0,
719 0,
720 0.9 * UI_UNIT_X,
721 UI_UNIT_Y,
722 nullptr,
723 0.0,
724 0.0,
725 TIP_("Delete envelope control point"));
728 }
729
731}
732
733static void panel_register_envelope(ARegionType *region_type,
734 const char *id_prefix,
735 PanelTypePollFn poll_fn)
736{
738 region_type, FMODIFIER_TYPE_ENVELOPE, envelope_panel_draw, poll_fn, id_prefix);
739 fmodifier_subpanel_register(region_type,
740 "frame_range",
741 "",
744 poll_fn,
745 panel_type);
746}
747
750/* -------------------------------------------------------------------- */
754static void limits_panel_draw(const bContext *C, Panel *panel)
755{
756 uiLayout *col, *row, *sub;
757 uiLayout *layout = panel->layout;
758
759 PointerRNA *ptr = fmodifier_get_pointers(C, panel, nullptr);
760
761 uiLayoutSetPropSep(layout, true);
762 uiLayoutSetPropDecorate(layout, false);
763
764 /* Minimums. */
765 col = uiLayoutColumn(layout, false);
766 row = uiLayoutRowWithHeading(col, true, IFACE_("Minimum X"));
767 uiItemR(row, ptr, "use_min_x", UI_ITEM_NONE, "", ICON_NONE);
768 sub = uiLayoutColumn(row, true);
769 uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min_x"));
770 uiItemR(sub, ptr, "min_x", UI_ITEM_NONE, "", ICON_NONE);
771
772 row = uiLayoutRowWithHeading(col, true, IFACE_("Y"));
773 uiItemR(row, ptr, "use_min_y", UI_ITEM_NONE, "", ICON_NONE);
774 sub = uiLayoutColumn(row, true);
775 uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min_y"));
776 uiItemR(sub, ptr, "min_y", UI_ITEM_NONE, "", ICON_NONE);
777
778 /* Maximums. */
779 col = uiLayoutColumn(layout, false);
780 row = uiLayoutRowWithHeading(col, true, IFACE_("Maximum X"));
781 uiItemR(row, ptr, "use_max_x", UI_ITEM_NONE, "", ICON_NONE);
782 sub = uiLayoutColumn(row, true);
783 uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max_x"));
784 uiItemR(sub, ptr, "max_x", UI_ITEM_NONE, "", ICON_NONE);
785
786 row = uiLayoutRowWithHeading(col, true, IFACE_("Y"));
787 uiItemR(row, ptr, "use_max_y", UI_ITEM_NONE, "", ICON_NONE);
788 sub = uiLayoutColumn(row, true);
789 uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max_y"));
790 uiItemR(sub, ptr, "max_y", UI_ITEM_NONE, "", ICON_NONE);
791
793}
794
795static void panel_register_limits(ARegionType *region_type,
796 const char *id_prefix,
797 PanelTypePollFn poll_fn)
798{
800 region_type, FMODIFIER_TYPE_LIMITS, limits_panel_draw, poll_fn, id_prefix);
801 fmodifier_subpanel_register(region_type,
802 "frame_range",
803 "",
806 poll_fn,
807 panel_type);
808}
809
812/* -------------------------------------------------------------------- */
816static void stepped_panel_draw(const bContext *C, Panel *panel)
817{
818 uiLayout *col, *sub, *row;
819 uiLayout *layout = panel->layout;
820
821 PointerRNA *ptr = fmodifier_get_pointers(C, panel, nullptr);
822
823 uiLayoutSetPropSep(layout, true);
824 uiLayoutSetPropDecorate(layout, false);
825
826 /* Stepping Settings. */
827 col = uiLayoutColumn(layout, false);
828 uiItemR(col, ptr, "frame_step", UI_ITEM_NONE, nullptr, ICON_NONE);
829 uiItemR(col, ptr, "frame_offset", UI_ITEM_NONE, nullptr, ICON_NONE);
830
831 /* Start range settings. */
832 row = uiLayoutRowWithHeading(layout, true, IFACE_("Start Frame"));
833 uiItemR(row, ptr, "use_frame_start", UI_ITEM_NONE, "", ICON_NONE);
834 sub = uiLayoutColumn(row, true);
835 uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_frame_start"));
836 uiItemR(sub, ptr, "frame_start", UI_ITEM_NONE, "", ICON_NONE);
837
838 /* End range settings. */
839 row = uiLayoutRowWithHeading(layout, true, IFACE_("End Frame"));
840 uiItemR(row, ptr, "use_frame_end", UI_ITEM_NONE, "", ICON_NONE);
841 sub = uiLayoutColumn(row, true);
842 uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_frame_end"));
843 uiItemR(sub, ptr, "frame_end", UI_ITEM_NONE, "", ICON_NONE);
844
846}
847
848static void panel_register_stepped(ARegionType *region_type,
849 const char *id_prefix,
850 PanelTypePollFn poll_fn)
851{
853 region_type, FMODIFIER_TYPE_STEPPED, stepped_panel_draw, poll_fn, id_prefix);
854 fmodifier_subpanel_register(region_type,
855 "frame_range",
856 "",
859 poll_fn,
860 panel_type);
861}
862
865/* -------------------------------------------------------------------- */
870 ID *owner_id,
871 ListBase *fmodifiers,
872 uiListPanelIDFromDataFunc panel_id_fn)
873{
874 ARegion *region = CTX_wm_region(C);
875
876 bool panels_match = UI_panel_list_matches_data(region, fmodifiers, panel_id_fn);
877
878 if (!panels_match) {
879 UI_panels_free_instanced(C, region);
880 LISTBASE_FOREACH (FModifier *, fcm, fmodifiers) {
881 char panel_idname[MAX_NAME];
882 panel_id_fn(fcm, panel_idname);
883
884 PointerRNA *fcm_ptr = static_cast<PointerRNA *>(
885 MEM_mallocN(sizeof(PointerRNA), "panel customdata"));
886 *fcm_ptr = RNA_pointer_create(owner_id, &RNA_FModifier, fcm);
887
888 UI_panel_add_instanced(C, region, &region->panels, panel_idname, fcm_ptr);
889 }
890 }
891 else {
892 /* Assuming there's only one group of instanced panels, update the custom data pointers. */
893 Panel *panel = static_cast<Panel *>(region->panels.first);
894 LISTBASE_FOREACH (FModifier *, fcm, fmodifiers) {
895
896 /* Move to the next instanced panel corresponding to the next modifier. */
897 while ((panel->type == nullptr) || !(panel->type->flag & PANEL_TYPE_INSTANCED)) {
898 panel = panel->next;
899 BLI_assert(panel !=
900 nullptr); /* There shouldn't be fewer panels than modifiers with UIs. */
901 }
902
903 PointerRNA *fcm_ptr = MEM_new<PointerRNA>("panel customdata");
904 *fcm_ptr = RNA_pointer_create(owner_id, &RNA_FModifier, fcm);
905 UI_panel_custom_data_set(panel, fcm_ptr);
906
907 panel = panel->next;
908 }
909 }
910}
911
913 const char *modifier_panel_prefix,
914 PanelTypePollFn poll_function)
915{
916 panel_register_generator(region_type, modifier_panel_prefix, poll_function);
917 panel_register_fn_generator(region_type, modifier_panel_prefix, poll_function);
918 panel_register_noise(region_type, modifier_panel_prefix, poll_function);
919 panel_register_envelope(region_type, modifier_panel_prefix, poll_function);
920 panel_register_limits(region_type, modifier_panel_prefix, poll_function);
921 panel_register_stepped(region_type, modifier_panel_prefix, poll_function);
922}
923
925 const char *modifier_panel_prefix,
926 PanelTypePollFn poll_function)
927{
928 panel_register_cycles(region_type, modifier_panel_prefix, poll_function);
929}
930
933/* -------------------------------------------------------------------- */
940/* Copy/Paste Buffer itself (list of FModifier 's) */
941static ListBase fmodifier_copypaste_buf = {nullptr, nullptr};
942
943/* ---------- */
944
946{
947 /* just free the whole buffer */
949}
950
951bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
952{
953 bool ok = true;
954
955 /* sanity checks */
956 if (ELEM(nullptr, modifiers, modifiers->first)) {
957 return false;
958 }
959
960 /* copy the whole list, or just the active one? */
961 if (active) {
962 FModifier *fcm = find_active_fmodifier(modifiers);
963
964 if (fcm) {
965 FModifier *fcmN = copy_fmodifier(fcm);
967 }
968 else {
969 ok = false;
970 }
971 }
972 else {
974 }
975
976 /* did we succeed? */
977 return ok;
978}
979
980bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
981{
982 bool ok = false;
983
984 /* sanity checks */
985 if (modifiers == nullptr) {
986 return false;
987 }
988
989 bool was_cyclic = curve && BKE_fcurve_is_cyclic(curve);
990
991 /* if replacing the list, free the existing modifiers */
992 if (replace) {
993 free_fmodifiers(modifiers);
994 }
995
996 /* now copy over all the modifiers in the buffer to the end of the list */
998 /* make a copy of it */
999 FModifier *fcmN = copy_fmodifier(fcm);
1000
1001 fcmN->curve = curve;
1002
1003 /* make sure the new one isn't active, otherwise the list may get several actives */
1004 fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE;
1005
1006 /* now add it to the end of the list */
1007 BLI_addtail(modifiers, fcmN);
1008 ok = true;
1009 }
1010
1011 /* adding or removing the Cycles modifier requires an update to handles */
1012 if (curve && BKE_fcurve_is_cyclic(curve) != was_cyclic) {
1014 }
1015
1016 /* did we succeed? */
1017 return ok;
1018}
1019
SpaceGraph * CTX_wm_space_graph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
int BKE_fcm_envelope_find_index(FCM_EnvelopeData *array, float frame, int arraylen, bool *r_exists)
bool BKE_fcurve_is_cyclic(const FCurve *fcu)
FModifier * copy_fmodifier(const FModifier *src)
const FModifierTypeInfo * get_fmodifier_typeinfo(int type)
void copy_fmodifiers(ListBase *dst, const ListBase *src)
void BKE_fcurve_handles_recalc(FCurve *fcu)
bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
@ FMI_REQUIRES_ORIGINAL_DATA
FModifier * find_active_fmodifier(ListBase *modifiers)
void free_fmodifiers(ListBase *modifiers)
const FModifierTypeInfo * fmodifier_get_typeinfo(const FModifier *fcm)
@ PANEL_TYPE_INSTANCED
@ PANEL_TYPE_DEFAULT_CLOSED
@ PANEL_TYPE_HEADER_EXPAND
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void void void bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL()
Definition listbase.cc:435
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
struct LinkData * BLI_genericNodeN(void *data)
Definition listbase.cc:909
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define BLT_I18NCONTEXT_ID_ACTION
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1044
eFModifier_Types
@ FMODIFIER_TYPE_CYCLES
@ FMODIFIER_TYPE_STEPPED
@ FMODIFIER_TYPE_FN_GENERATOR
@ FMODIFIER_TYPE_NOISE
@ FMODIFIER_TYPE_GENERATOR
@ FMODIFIER_TYPE_ENVELOPE
@ FMODIFIER_TYPE_LIMITS
@ FCM_GENERATOR_POLYNOMIAL_FACTORISED
@ FCM_GENERATOR_POLYNOMIAL
@ FMODIFIER_FLAG_USEINFLUENCE
@ FMODIFIER_FLAG_RANGERESTRICT
@ FCURVE_MOD_OFF
#define MAX_NAME
Definition DNA_defs.h:50
@ SPACE_NLA
@ SPACE_GRAPH
void(*)(void *data_link, char *r_idname) uiListPanelIDFromDataFunc
NlaStrip * ANIM_nla_context_strip(const bContext *C)
FCurve * ANIM_graph_context_fcurve(const bContext *C)
bool(*)(const bContext *C, PanelType *pt) PanelTypePollFn
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:104
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
void UI_but_func_set(uiBut *but, std::function< void(bContext &)> func)
#define UI_UNIT_Y
void uiLayoutSetActive(uiLayout *layout, bool active)
@ UI_EMBOSS_NONE
@ UI_LAYOUT_ALIGN_RIGHT
uiBut * uiDefBut(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
void uiItemL(uiLayout *layout, const char *name, int icon)
void UI_panels_free_instanced(const bContext *C, ARegion *region)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, const char *name, int icon, const char *placeholder=nullptr)
uiBut * uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemS(uiLayout *layout)
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data)
#define UI_ITEM_NONE
void UI_block_align_begin(uiBlock *block)
void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
bool UI_panel_list_matches_data(ARegion *region, ListBase *data, uiListPanelIDFromDataFunc panel_idname_func)
#define UI_UNIT_X
@ UI_BTYPE_BUT
PointerRNA * UI_panel_custom_data_get(const Panel *panel)
void UI_but_funcN_set(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2, uiButArgNFree func_argN_free_fn=MEM_freeN, uiButArgNCopy func_argN_copy_fn=MEM_dupallocN)
Panel * UI_panel_add_instanced(const bContext *C, ARegion *region, ListBase *panels, const char *panel_idname, PointerRNA *custom_data)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_ICON_ONLY
#define NC_ANIMATION
Definition WM_types.hh:355
#define NA_EDITED
Definition WM_types.hh:550
#define ND_KEYFRAME
Definition WM_types.hh:461
const char * label
draw_view in_light_buf[] float
#define B_FMODIFIER_REDRAW
static void delete_fmodifier_cb(bContext *C, void *ctx_v, void *fcm_v)
static void panel_register_noise(ARegionType *region_type, const char *id_prefix, PanelTypePollFn poll_fn)
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
static void fmodifier_frame_range_draw(const bContext *C, Panel *panel)
static void fmodifier_panel_header(const bContext *C, Panel *panel)
static void fmod_envelope_deletepoint_cb(bContext *, void *fcm_dv, void *ind_v)
static void cycles_panel_draw(const bContext *C, Panel *panel)
static PointerRNA * fmodifier_get_pointers(const bContext *C, const Panel *panel, ID **r_owner_id)
static PanelType * fmodifier_panel_register(ARegionType *region_type, eFModifier_Types type, PanelDrawFn draw, PanelTypePollFn poll, const char *id_prefix)
static void panel_register_stepped(ARegionType *region_type, const char *id_prefix, PanelTypePollFn poll_fn)
static void fmodifier_frame_range_header_draw(const bContext *C, Panel *panel)
static void fmodifier_reorder(bContext *C, Panel *panel, int new_index)
static void generator_panel_draw(const bContext *C, Panel *panel)
void(*)(const bContext *, Panel *) PanelDrawFn
static void fn_generator_panel_draw(const bContext *C, Panel *panel)
#define B_REDR
static void panel_register_cycles(ARegionType *region_type, const char *id_prefix, PanelTypePollFn poll_fn)
static void noise_panel_draw(const bContext *C, Panel *panel)
static ListBase fmodifier_copypaste_buf
void ANIM_modifier_panels_register_graph_only(ARegionType *region_type, const char *modifier_panel_prefix, PanelTypePollFn poll_function)
static void fmodifier_influence_draw(uiLayout *layout, PointerRNA *ptr)
void ANIM_modifier_panels_register_graph_and_NLA(ARegionType *region_type, const char *modifier_panel_prefix, PanelTypePollFn poll_function)
static ListBase * fmodifier_list_space_specific(const bContext *C)
static void panel_register_limits(ARegionType *region_type, const char *id_prefix, PanelTypePollFn poll_fn)
static void panel_register_envelope(ARegionType *region_type, const char *id_prefix, PanelTypePollFn poll_fn)
void ANIM_fmodifiers_copybuf_free()
static void set_fmodifier_expand_flag(const bContext *, Panel *panel, short expand_flag)
static PanelType * fmodifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelTypePollFn poll, PanelType *parent)
static void panel_register_generator(ARegionType *region_type, const char *id_prefix, PanelTypePollFn poll_fn)
static void limits_panel_draw(const bContext *C, Panel *panel)
static void envelope_panel_draw(const bContext *C, Panel *panel)
static void fmod_envelope_addpoint_cb(bContext *C, void *fcm_dv, void *)
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
static void stepped_panel_draw(const bContext *C, Panel *panel)
void ANIM_fmodifier_panels(const bContext *C, ID *owner_id, ListBase *fmodifiers, uiListPanelIDFromDataFunc panel_id_fn)
static short get_fmodifier_expand_flag(const bContext *, Panel *panel)
static void panel_register_fn_generator(ARegionType *region_type, const char *id_prefix, PanelTypePollFn poll_fn)
uint col
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
ListBase paneltypes
ListBase modifiers
FCM_EnvelopeData * data
struct FCurve * curve
short ui_expand_flag
Definition DNA_ID.h:413
void * first
ListBase modifiers
void(* reorder)(bContext *C, Panel *pa, int new_index)
void(* set_list_data_expand_flag)(const bContext *C, Panel *pa, short expand_flag)
void(* draw)(const bContext *C, Panel *panel)
char idname[BKE_ST_MAXNAME]
bool(* poll)(const bContext *C, PanelType *pt)
char translation_context[BKE_ST_MAXNAME]
ListBase children
char category[BKE_ST_MAXNAME]
char label[BKE_ST_MAXNAME]
short(* get_list_data_expand_flag)(const bContext *C, Panel *pa)
char parent_id[BKE_ST_MAXNAME]
PanelType * parent
void(* draw_header)(const bContext *C, Panel *panel)
struct PanelType * type
struct uiLayout * layout
struct Panel * next
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
#define N_(msgid)
void WM_report(eReportType type, const char *message)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4126