diff options
Diffstat (limited to 'source/blender/editors/animation/fmodifier_ui.c')
-rw-r--r-- | source/blender/editors/animation/fmodifier_ui.c | 1449 |
1 files changed, 684 insertions, 765 deletions
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index deebf1d1efc..c17d678d866 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -32,6 +32,7 @@ #include "DNA_anim_types.h" #include "DNA_scene_types.h" +#include "DNA_space_types.h" #include "MEM_guardedalloc.h" @@ -42,6 +43,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_screen.h" #include "WM_api.h" #include "WM_types.h" @@ -56,47 +58,208 @@ #include "DEG_depsgraph.h" -/* ********************************************** */ -/* UI STUFF */ +typedef void (*PanelDrawFn)(const bContext *, struct Panel *); +static void fmodifier_panel_header(const bContext *C, Panel *panel); -/* XXX! -------------------------------- */ -/* Temporary definition for limits of float number buttons - * (FLT_MAX tends to infinity with old system). */ -#define UI_FLT_MAX 10000.0f +/* -------------------------------------------------------------------- */ +/** \name Panel Registering and Panel Callbacks + * \{ */ -#define B_REDR 1 -#define B_FMODIFIER_REDRAW 20 +/** + * Get the list of FModifiers from the context (either the NLA or graph editor). + */ +static ListBase *fmodifier_list_space_specific(const bContext *C) +{ + ScrArea *area = CTX_wm_area(C); + + if (area->spacetype == SPACE_GRAPH) { + FCurve *fcu = ANIM_graph_context_fcurve(C); + return &fcu->modifiers; + } + + if (area->spacetype == SPACE_NLA) { + NlaStrip *strip = ANIM_nla_context_strip(C); + return &strip->modifiers; + } -/* callback to update depsgraph on value changes */ -static void deg_update(bContext *C, void *owner_id, void *UNUSED(var2)) + /* This should not be called in any other space. */ + BLI_assert(false); + return NULL; +} + +/** + * Get a pointer to the panel's FModifier, and also its owner ID if \a r_owner_id is not NULL. + * Also in the graph editor, gray out the panel if the FModifier's FCurve has modifiers turned off. + */ +static PointerRNA *fmodifier_get_pointers(const bContext *C, const Panel *panel, ID **r_owner_id) { - /* send notifiers */ - /* 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. */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - DEG_id_tag_update(owner_id, ID_RECALC_ANIMATION); + PointerRNA *ptr = UI_panel_custom_data_get(panel); + + if (r_owner_id != NULL) { + *r_owner_id = ptr->owner_id; + } + + if (C != NULL && CTX_wm_space_graph(C)) { + FCurve *fcu = ANIM_graph_context_fcurve(C); + uiLayoutSetActive(panel->layout, !(fcu->flag & FCURVE_MOD_OFF)); + } + + return ptr; } -/* callback to verify modifier data */ -static void validate_fmodifier_cb(bContext *C, void *fcm_v, void *owner_id) +/** + * Move an FModifier to the index it's moved to after a drag and drop. + */ +static void fmodifier_reorder(bContext *C, Panel *panel, int new_index) { - FModifier *fcm = (FModifier *)fcm_v; - const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + ID *owner_id; + PointerRNA *ptr = fmodifier_get_pointers(NULL, panel, &owner_id); + FModifier *fcm = ptr->data; + const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(fcm->type); + + /* Cycles modifier has to be the first, so make sure it's kept that way. */ + if (fmi->requires & FMI_REQUIRES_ORIGINAL_DATA) { + WM_report(RPT_ERROR, "Modifier requires original data"); + return; + } - /* call the verify callback on the modifier if applicable */ - if (fmi && fmi->verify_data) { - fmi->verify_data(fcm); + ListBase *modifiers = fmodifier_list_space_specific(C); + + /* Again, make sure we don't move a modifier before a cycles modifier. */ + FModifier *fcm_first = modifiers->first; + const FModifierTypeInfo *fmi_first = get_fmodifier_typeinfo(fcm_first->type); + if (fmi_first->requires & FMI_REQUIRES_ORIGINAL_DATA && new_index == 0) { + WM_report(RPT_ERROR, "Modifier requires original data"); + return; } - if (owner_id) { - deg_update(C, owner_id, NULL); + + int current_index = BLI_findindex(modifiers, fcm); + BLI_assert(current_index >= 0); + BLI_assert(new_index >= 0); + + /* Don't do anything if the drag didn't change the index. */ + if (current_index == new_index) { + return; } + + /* Move the FModifier in the list. */ + BLI_listbase_link_move(modifiers, fcm, new_index - current_index); + + ED_undo_push(C, "Reorder F-Curve Modifier"); + + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + DEG_id_tag_update(owner_id, ID_RECALC_ANIMATION); +} + +static short get_fmodifier_expand_flag(const bContext *UNUSED(C), Panel *panel) +{ + PointerRNA *ptr = fmodifier_get_pointers(NULL, panel, NULL); + FModifier *fcm = (FModifier *)ptr->data; + + return fcm->ui_expand_flag; +} + +static void set_fmodifier_expand_flag(const bContext *UNUSED(C), Panel *panel, short expand_flag) +{ + PointerRNA *ptr = fmodifier_get_pointers(NULL, panel, NULL); + FModifier *fcm = (FModifier *)ptr->data; + + fcm->ui_expand_flag = expand_flag; +} + +static PanelType *fmodifier_panel_register(ARegionType *region_type, + eFModifier_Types type, + PanelDrawFn draw, + PanelTypePollFn poll, + const char *id_prefix) +{ + /* Get the name for the modifier's panel. */ + char panel_idname[BKE_ST_MAXNAME]; + const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type); + BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_PT_%s", id_prefix, fmi->name); + + PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + + /* Intentionally leave the label field blank. The header is filled with buttons. */ + BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME); + BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); + + panel_type->draw_header = fmodifier_panel_header; + panel_type->draw = draw; + panel_type->poll = poll; + + /* Give the panel the special flag that says it was built here and corresponds to a + * modifer rather than a PanelType. */ + panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_DRAW_BOX | PANEL_TYPE_INSTANCED; + panel_type->reorder = fmodifier_reorder; + panel_type->get_list_data_expand_flag = get_fmodifier_expand_flag; + panel_type->set_list_data_expand_flag = set_fmodifier_expand_flag; + + BLI_addtail(®ion_type->paneltypes, panel_type); + + return panel_type; } +/** + * Add a child panel to the parent. + * + * \note To create the panel type's idname, it appends the \a name argument to the \a parent's + * idname. + */ +static PanelType *fmodifier_subpanel_register(ARegionType *region_type, + const char *name, + const char *label, + PanelDrawFn draw_header, + PanelDrawFn draw, + PanelTypePollFn poll, + PanelType *parent) +{ + /* Create the subpanel's ID name. */ + char panel_idname[BKE_ST_MAXNAME]; + BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); + + PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + + BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME); + BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME); + BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); + + panel_type->draw_header = draw_header; + panel_type->draw = draw; + panel_type->poll = poll; + panel_type->flag = PANEL_TYPE_DEFAULT_CLOSED | PANEL_TYPE_DRAW_BOX; + + BLI_assert(parent != NULL); + BLI_strncpy(panel_type->parent_id, parent->idname, BKE_ST_MAXNAME); + panel_type->parent = parent; + BLI_addtail(&parent->children, BLI_genericNodeN(panel_type)); + BLI_addtail(®ion_type->paneltypes, panel_type); + + return panel_type; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name General UI Callbacks and Drawing + * \{ */ + +/* XXX! -------------------------------- */ +/* Temporary definition for limits of float number buttons + * (FLT_MAX tends to infinity with old system). */ +#define UI_FLT_MAX 10000.0f + +#define B_REDR 1 +#define B_FMODIFIER_REDRAW 20 + /* callback to remove the given modifier */ typedef struct FModifierDeleteContext { - ID *fcurve_owner_id; + ID *owner_id; ListBase *modifiers; } FModifierDeleteContext; + static void delete_fmodifier_cb(bContext *C, void *ctx_v, void *fcm_v) { FModifierDeleteContext *ctx = (FModifierDeleteContext *)ctx_v; @@ -108,466 +271,334 @@ static void delete_fmodifier_cb(bContext *C, void *ctx_v, void *fcm_v) ED_undo_push(C, "Delete F-Curve Modifier"); - deg_update(C, ctx->fcurve_owner_id, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + DEG_id_tag_update(ctx->owner_id, ID_RECALC_ANIMATION); } -/* --------------- */ -/* draw settings for generator modifier */ -static void draw_modifier__generator(uiLayout *layout, - ID *fcurve_owner_id, - FModifier *fcm, - short width) +static void fmodifier_influence_draw(uiLayout *layout, PointerRNA *ptr) { + FModifier *fcm = (FModifier *)ptr->data; + uiItemS(layout); + + uiLayout *row = uiLayoutRowWithHeading(layout, true, IFACE_("Influence")); + uiItemR(row, ptr, "use_influence", 0, "", ICON_NONE); + uiLayout *sub = uiLayoutRow(row, true); + + uiLayoutSetActive(sub, fcm->flag & FMODIFIER_FLAG_USEINFLUENCE); + uiItemR(sub, ptr, "influence", 0, "", ICON_NONE); +} + +static void fmodifier_frame_range_header_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL); + + uiItemR(layout, ptr, "use_restricted_range", 0, NULL, ICON_NONE); +} + +static void fmodifier_frame_range_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL); + + uiLayoutSetPropSep(layout, true); + + FModifier *fcm = (FModifier *)ptr->data; + uiLayoutSetActive(layout, fcm->flag & FMODIFIER_FLAG_RANGERESTRICT); + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE); + uiItemR(col, ptr, "frame_end", 0, IFACE_("End"), ICON_NONE); + + col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "blend_in", 0, IFACE_("Blend In"), ICON_NONE); + uiItemR(col, ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE); +} + +static void fmodifier_panel_header(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + ID *owner_id; + PointerRNA *ptr = fmodifier_get_pointers(C, panel, &owner_id); + FModifier *fcm = (FModifier *)ptr->data; + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + + uiBlock *block = uiLayoutGetBlock(layout); + + uiLayout *sub = uiLayoutRow(layout, true); + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); + uiLayoutSetEmboss(sub, UI_EMBOSS_NONE); + + /* Checkbox for 'active' status (for now). */ + uiItemR(sub, ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + + /* Name. */ + if (fmi) { + uiItemL(sub, IFACE_(fmi->name), ICON_NONE); + } + else { + uiItemL(sub, IFACE_("<Unknown Modifier>"), ICON_NONE); + } + + /* Right align. */ + sub = uiLayoutRow(layout, true); + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); + uiLayoutSetEmboss(sub, UI_EMBOSS_NONE); + + /* 'Mute' button. */ + uiItemR(sub, ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + + /* Delete button. */ + uiBut *but = uiDefIconBut(block, + UI_BTYPE_BUT, + B_REDR, + ICON_X, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + TIP_("Delete Modifier")); + FModifierDeleteContext *ctx = MEM_mallocN(sizeof(FModifierDeleteContext), __func__); + ctx->owner_id = owner_id; + ctx->modifiers = fmodifier_list_space_specific(C); + BLI_assert(ctx->modifiers != NULL); + + UI_but_funcN_set(but, delete_fmodifier_cb, ctx, fcm); + + uiItemS(layout); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Generator Modifier + * \{ */ + +static void generator_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + ID *owner_id; + PointerRNA *ptr = fmodifier_get_pointers(C, panel, &owner_id); + FModifier *fcm = (FModifier *)ptr->data; FMod_Generator *data = (FMod_Generator *)fcm->data; - uiLayout /* *col, */ /* UNUSED */ *row; - uiBlock *block; - uiBut *but; - PointerRNA ptr; - short bwidth = width - 1.5 * UI_UNIT_X; /* max button width */ - - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierFunctionGenerator, fcm, &ptr); - - /* basic settings (backdrop + mode selector + some padding) */ - /* col = uiLayoutColumn(layout, true); */ /* UNUSED */ - block = uiLayoutGetBlock(layout); - UI_block_align_begin(block); - but = uiDefButR(block, - UI_BTYPE_MENU, - B_FMODIFIER_REDRAW, - NULL, - 0, - 0, - bwidth, - UI_UNIT_Y, - &ptr, - "mode", - -1, - 0, - 0, - -1, - -1, - NULL); - UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL); - - uiDefButR(block, - UI_BTYPE_TOGGLE, - B_FMODIFIER_REDRAW, - NULL, - 0, - 0, - bwidth, - UI_UNIT_Y, - &ptr, - "use_additive", - -1, - 0, - 0, - -1, - -1, - NULL); - UI_block_align_end(block); - - /* now add settings for individual modes */ + + uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + + uiItemR(layout, ptr, "use_additive", 0, NULL, ICON_NONE); + + uiItemR(layout, ptr, "poly_order", 0, IFACE_("Order"), ICON_NONE); + + PropertyRNA *prop = RNA_struct_find_property(ptr, "coefficients"); + uiLayout *col = uiLayoutColumn(layout, true); switch (data->mode) { - case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */ + case FCM_GENERATOR_POLYNOMIAL: /* Polynomial expression. */ { - const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - float *cp = NULL; + char xval[32]; - int maxXWidth; - - /* draw polynomial order selector */ - row = uiLayoutRow(layout, false); - block = uiLayoutGetBlock(row); - - but = uiDefButI( - block, - UI_BTYPE_NUM, - B_FMODIFIER_REDRAW, - IFACE_("Poly Order:"), - 0.5f * UI_UNIT_X, - 0, - bwidth, - UI_UNIT_Y, - &data->poly_order, - 1, - 100, - 0, - 0, - TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)")); - UI_but_number_step_size_set(but, 1); - UI_but_func_set(but, validate_fmodifier_cb, fcm, fcurve_owner_id); - - /* calculate maximum width of label for "x^n" labels */ - if (data->arraysize > 2) { - BLI_snprintf(xval, sizeof(xval), "x^%u", data->arraysize); - /* XXX: UI_fontstyle_string_width is not accurate */ - maxXWidth = UI_fontstyle_string_width(fstyle, xval) + 0.5 * UI_UNIT_X; - } - else { - /* basic size (just "x") */ - maxXWidth = UI_fontstyle_string_width(fstyle, "x") + 0.5 * UI_UNIT_X; - } - /* draw controls for each coefficient and a + sign at end of row */ - row = uiLayoutRow(layout, true); - block = uiLayoutGetBlock(row); - - /* Update depsgraph when values change */ - UI_block_func_set(block, deg_update, fcurve_owner_id, NULL); - - cp = data->coefficients; - for (uint i = 0; (i < data->arraysize) && (cp); i++, cp++) { - /* To align with first line... */ - if (i) { - uiDefBut(block, - UI_BTYPE_LABEL, - 1, - " ", - 0, - 0, - 2 * UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - } - else { - uiDefBut(block, - UI_BTYPE_LABEL, - 1, - "y =", - 0, - 0, - 2 * UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - } - - /* coefficient */ - but = uiDefButF(block, - UI_BTYPE_NUM, - B_FMODIFIER_REDRAW, - "", - 0, - 0, - bwidth / 2, - UI_UNIT_Y, - cp, - -UI_FLT_MAX, - UI_FLT_MAX, - 0, - 0, - TIP_("Coefficient for polynomial")); - UI_but_number_step_size_set(but, 10); - UI_but_number_precision_set(but, 3); - - /* 'x' param (and '+' if necessary) */ - if (i == 0) { - BLI_strncpy(xval, " ", sizeof(xval)); - } - else if (i == 1) { - BLI_strncpy(xval, "x", sizeof(xval)); - } - else { - BLI_snprintf(xval, sizeof(xval), "x^%u", i); - } - uiDefBut(block, - UI_BTYPE_LABEL, - 1, - xval, - 0, - 0, - maxXWidth, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - TIP_("Power of x")); - - if ((i != (data->arraysize - 1)) || ((i == 0) && data->arraysize == 2)) { - uiDefBut( - block, UI_BTYPE_LABEL, 1, "+", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - /* next coefficient on a new row */ - row = uiLayoutRow(layout, true); - block = uiLayoutGetBlock(row); - } - else { - /* For alignment in UI! */ - uiDefBut( - block, UI_BTYPE_LABEL, 1, " ", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - } + /* The first value gets a "Coefficient" label. */ + BLI_strncpy(xval, "Coefficient", sizeof(xval)); + + for (int i = 0; i < data->arraysize; i++) { + uiItemFullR(col, ptr, prop, i, 0, 0, N_(xval), ICON_NONE); + BLI_snprintf(xval, sizeof(xval), "x^%d", i + 1); } break; } - case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial expression */ { - float *cp = NULL; - - /* draw polynomial order selector */ - row = uiLayoutRow(layout, false); - block = uiLayoutGetBlock(row); - - but = uiDefButI( - block, - UI_BTYPE_NUM, - B_FMODIFIER_REDRAW, - IFACE_("Poly Order:"), - 0, - 0, - width - 1.5 * UI_UNIT_X, - UI_UNIT_Y, - &data->poly_order, - 1, - 100, - 0, - 0, - TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)")); - UI_but_func_set(but, validate_fmodifier_cb, fcm, fcurve_owner_id); - UI_but_number_step_size_set(but, 1); - - /* draw controls for each pair of coefficients */ - row = uiLayoutRow(layout, true); - block = uiLayoutGetBlock(row); - - /* Update depsgraph when values change */ - UI_block_func_set(block, deg_update, fcurve_owner_id, NULL); - - cp = data->coefficients; - for (uint i = 0; (i < data->poly_order) && (cp); i++, cp += 2) { - /* To align with first line */ - if (i) { - uiDefBut(block, - UI_BTYPE_LABEL, - 1, - " ", - 0, - 0, - 2.5 * UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - } - else { - uiDefBut(block, - UI_BTYPE_LABEL, - 1, - "y =", - 0, - 0, - 2.5 * UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - } - /* opening bracket */ - uiDefBut( - block, UI_BTYPE_LABEL, 1, "(", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - /* coefficients */ - but = uiDefButF(block, - UI_BTYPE_NUM, - B_FMODIFIER_REDRAW, - "", - 0, - 0, - 5 * UI_UNIT_X, - UI_UNIT_Y, - cp, - -UI_FLT_MAX, - UI_FLT_MAX, - 0, - 0, - TIP_("Coefficient of x")); - UI_but_number_step_size_set(but, 10); - UI_but_number_precision_set(but, 3); - - uiDefBut(block, - UI_BTYPE_LABEL, - 1, - "x +", - 0, - 0, - 2 * UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - - but = 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, - 0, - 0, - TIP_("Second coefficient")); - UI_but_number_step_size_set(but, 10); - UI_but_number_precision_set(but, 3); - - /* closing bracket and multiplication sign */ - if ((i != (data->poly_order - 1)) || ((i == 0) && data->poly_order == 2)) { - uiDefBut(block, - UI_BTYPE_LABEL, - 1, - ") \xc3\x97", - 0, - 0, - 2 * UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - - /* set up new row for the next pair of coefficients */ - row = uiLayoutRow(layout, true); - block = uiLayoutGetBlock(row); - } - else { - uiDefBut(block, - UI_BTYPE_LABEL, - 1, - ") ", - 0, - 0, - 2 * UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - } + { + /* Add column labels above the buttons to prevent confusion. + * Fake the property split layout, otherwise the labels use the full row. */ + uiLayout *split = uiLayoutSplit(col, 0.4f, false); + uiLayoutColumn(split, false); + uiLayout *title_col = uiLayoutColumn(split, false); + uiLayout *title_row = uiLayoutRow(title_col, true); + uiItemL(title_row, N_("A"), ICON_NONE); + uiItemL(title_row, N_("B"), ICON_NONE); + } + + uiLayout *first_row = uiLayoutRow(col, true); + uiItemFullR(first_row, ptr, prop, 0, 0, 0, N_("y = (Ax + B)"), ICON_NONE); + uiItemFullR(first_row, ptr, prop, 1, 0, 0, "", ICON_NONE); + for (int i = 2; i < data->arraysize - 1; i++) { + /* \u2715 is the multiplication symbol. */ + uiLayout *row = uiLayoutRow(col, true); + uiItemFullR(row, ptr, prop, i, 0, 0, N_("\u2715 (Ax + B)"), ICON_NONE); + uiItemFullR(row, ptr, prop, i + 1, 0, 0, "", ICON_NONE); } break; } } + + fmodifier_influence_draw(layout, ptr); } -/* --------------- */ +static void panel_register_generator(ARegionType *region_type, + const char *id_prefix, + PanelTypePollFn poll_fn) +{ + PanelType *panel_type = fmodifier_panel_register( + region_type, FMODIFIER_TYPE_GENERATOR, generator_panel_draw, poll_fn, id_prefix); + fmodifier_subpanel_register(region_type, + "frame_range", + "", + fmodifier_frame_range_header_draw, + fmodifier_frame_range_draw, + poll_fn, + panel_type); +} + +/** \} */ -/* draw settings for generator modifier */ -static void draw_modifier__fn_generator(uiLayout *layout, - ID *fcurve_owner_id, - FModifier *fcm, - short UNUSED(width)) +/* -------------------------------------------------------------------- */ +/** \name Function Generator Modifier + * \{ */ + +static void fn_generator_panel_draw(const bContext *C, Panel *panel) { uiLayout *col; - PointerRNA ptr; + uiLayout *layout = panel->layout; - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierFunctionGenerator, fcm, &ptr); + PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL); - /* add the settings */ - col = uiLayoutColumn(layout, true); - uiItemR(col, &ptr, "function_type", 0, "", ICON_NONE); - uiItemR(col, &ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); - - col = uiLayoutColumn(layout, false); /* no grouping for now */ - uiItemR(col, &ptr, "amplitude", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "phase_multiplier", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "phase_offset", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "value_offset", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "function_type", 0, "", ICON_NONE); + + uiLayoutSetPropSep(layout, true); + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "use_additive", 0, NULL, ICON_NONE); + + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "amplitude", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "phase_multiplier", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "phase_offset", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "value_offset", 0, NULL, ICON_NONE); + + fmodifier_influence_draw(layout, ptr); } -/* --------------- */ +static void panel_register_fn_generator(ARegionType *region_type, + const char *id_prefix, + PanelTypePollFn poll_fn) +{ + PanelType *panel_type = fmodifier_panel_register( + region_type, FMODIFIER_TYPE_FN_GENERATOR, fn_generator_panel_draw, poll_fn, id_prefix); + fmodifier_subpanel_register(region_type, + "frame_range", + "", + fmodifier_frame_range_header_draw, + fmodifier_frame_range_draw, + poll_fn, + panel_type); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Cycles Modifier + * \{ */ + +static void cycles_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col; + uiLayout *layout = panel->layout; + + PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL); + + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + + /* Before. */ + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "mode_before", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "cycles_before", 0, IFACE_("Count"), ICON_NONE); + + /* After. */ + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "mode_after", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "cycles_after", 0, IFACE_("Count"), ICON_NONE); + + fmodifier_influence_draw(layout, ptr); +} -/* draw settings for cycles modifier */ -static void draw_modifier__cycles(uiLayout *layout, - ID *fcurve_owner_id, - FModifier *fcm, - short UNUSED(width)) +static void panel_register_cycles(ARegionType *region_type, + const char *id_prefix, + PanelTypePollFn poll_fn) { - uiLayout *split, *col; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierCycles, fcm, &ptr); - - /* split into 2 columns - * NOTE: the mode combination-boxes shouldn't get labels, otherwise there isn't enough room. */ - split = uiLayoutSplit(layout, 0.5f, false); - - /* before range */ - col = uiLayoutColumn(split, true); - uiItemL(col, IFACE_("Before:"), ICON_NONE); - uiItemR(col, &ptr, "mode_before", 0, "", ICON_NONE); - uiItemR(col, &ptr, "cycles_before", 0, NULL, ICON_NONE); - - /* after range */ - col = uiLayoutColumn(split, true); - uiItemL(col, IFACE_("After:"), ICON_NONE); - uiItemR(col, &ptr, "mode_after", 0, "", ICON_NONE); - uiItemR(col, &ptr, "cycles_after", 0, NULL, ICON_NONE); + PanelType *panel_type = fmodifier_panel_register( + region_type, FMODIFIER_TYPE_CYCLES, cycles_panel_draw, poll_fn, id_prefix); + fmodifier_subpanel_register(region_type, + "frame_range", + "", + fmodifier_frame_range_header_draw, + fmodifier_frame_range_draw, + poll_fn, + panel_type); } -/* --------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Noise Modifier + * \{ */ -/* draw settings for noise modifier */ -static void draw_modifier__noise(uiLayout *layout, - ID *fcurve_owner_id, - FModifier *fcm, - short UNUSED(width)) +static void noise_panel_draw(const bContext *C, Panel *panel) { - uiLayout *split, *col; - PointerRNA ptr; + uiLayout *col; + uiLayout *layout = panel->layout; - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierNoise, fcm, &ptr); + PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL); - /* blending mode */ - uiItemR(layout, &ptr, "blend_type", 0, NULL, ICON_NONE); + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); - /* split into 2 columns */ - split = uiLayoutSplit(layout, 0.5f, false); + uiItemR(layout, ptr, "blend_type", 0, NULL, ICON_NONE); - /* col 1 */ - col = uiLayoutColumn(split, false); - uiItemR(col, &ptr, "scale", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "offset", 0, NULL, ICON_NONE); + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "scale", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "strength", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "phase", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "depth", 0, NULL, ICON_NONE); - /* col 2 */ - col = uiLayoutColumn(split, false); - uiItemR(col, &ptr, "phase", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "depth", 0, NULL, ICON_NONE); + fmodifier_influence_draw(layout, ptr); +} + +static void panel_register_noise(ARegionType *region_type, + const char *id_prefix, + PanelTypePollFn poll_fn) +{ + PanelType *panel_type = fmodifier_panel_register( + region_type, FMODIFIER_TYPE_NOISE, noise_panel_draw, poll_fn, id_prefix); + fmodifier_subpanel_register(region_type, + "frame_range", + "", + fmodifier_frame_range_header_draw, + fmodifier_frame_range_draw, + poll_fn, + panel_type); } -/* callback to add new envelope data point */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Enevelope Modifier + * \{ */ + static void fmod_envelope_addpoint_cb(bContext *C, void *fcm_dv, void *UNUSED(arg)) { Scene *scene = CTX_data_scene(C); @@ -656,132 +687,60 @@ static void fmod_envelope_deletepoint_cb(bContext *UNUSED(C), void *fcm_dv, void } /* draw settings for envelope modifier */ -static void draw_modifier__envelope(uiLayout *layout, - ID *fcurve_owner_id, - FModifier *fcm, - short UNUSED(width)) +static void envelope_panel_draw(const bContext *C, Panel *panel) { + uiLayout *row, *col; + uiLayout *layout = panel->layout; + + ID *owner_id; + PointerRNA *ptr = fmodifier_get_pointers(C, panel, &owner_id); + FModifier *fcm = (FModifier *)ptr->data; FMod_Envelope *env = (FMod_Envelope *)fcm->data; - FCM_EnvelopeData *fed; - uiLayout *col, *row; - uiBlock *block; - uiBut *but; - PointerRNA ptr; - int i; - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierEnvelope, fcm, &ptr); + uiLayoutSetPropSep(layout, true); - /* general settings */ + /* General settings. */ col = uiLayoutColumn(layout, true); - uiItemL(col, IFACE_("Envelope:"), ICON_NONE); - uiItemR(col, &ptr, "reference_value", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "reference_value", 0, IFACE_("Reference"), ICON_NONE); + uiItemR(col, ptr, "default_min", 0, IFACE_("Min"), ICON_NONE); + uiItemR(col, ptr, "default_max", 0, IFACE_("Max"), ICON_NONE); - row = uiLayoutRow(col, true); - uiItemR(row, &ptr, "default_min", 0, IFACE_("Min"), ICON_NONE); - uiItemR(row, &ptr, "default_max", 0, IFACE_("Max"), ICON_NONE); + /* Control points list. */ - /* control points header */ - /* TODO: move this control-point control stuff to using the new special widgets for lists - * the current way is far too cramped */ row = uiLayoutRow(layout, false); - block = uiLayoutGetBlock(row); - - 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, - ""); - - but = uiDefBut(block, - UI_BTYPE_BUT, - B_FMODIFIER_REDRAW, - IFACE_("Add Point"), - 0, - 0, - 7.5 * UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Add a new control-point to the envelope on the current frame")); + uiBlock *block = uiLayoutGetBlock(row); + + uiBut *but = uiDefBut(block, + UI_BTYPE_BUT, + B_FMODIFIER_REDRAW, + IFACE_("Add Control Point"), + 0, + 0, + 7.5 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Add a new control-point to the envelope on the current frame")); UI_but_func_set(but, fmod_envelope_addpoint_cb, env, NULL); - /* control points list */ - for (i = 0, fed = env->data; i < env->totvert; i++, fed++) { + col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, false); + + FCM_EnvelopeData *fed = env->data; + for (int i = 0; i < env->totvert; i++, fed++) { PointerRNA ctrl_ptr; - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierEnvelopeControlPoint, fed, &ctrl_ptr); + RNA_pointer_create(owner_id, &RNA_FModifierEnvelopeControlPoint, fed, &ctrl_ptr); /* get a new row to operate on */ - row = uiLayoutRow(layout, true); + row = uiLayoutRow(col, true); block = uiLayoutGetBlock(row); - UI_block_align_begin(block); - but = uiDefButR(block, - UI_BTYPE_NUM, - B_FMODIFIER_REDRAW, - IFACE_("Fra:"), - 0, - 0, - 4.5 * UI_UNIT_X, - UI_UNIT_Y, - &ctrl_ptr, - "frame", - -1, - -MAXFRAMEF, - MAXFRAMEF, - 0, - 0, - NULL); - UI_but_number_step_size_set(but, 10); - UI_but_number_precision_set(but, 1); - but = uiDefButR(block, - UI_BTYPE_NUM, - B_FMODIFIER_REDRAW, - IFACE_("Min:"), - 0, - 0, - 5 * UI_UNIT_X, - UI_UNIT_Y, - &ctrl_ptr, - "min", - -1, - -UI_FLT_MAX, - UI_FLT_MAX, - 0, - 0, - NULL); - UI_but_number_step_size_set(but, 10); - UI_but_number_precision_set(but, 2); - but = uiDefButR(block, - UI_BTYPE_NUM, - B_FMODIFIER_REDRAW, - IFACE_("Max:"), - 0, - 0, - 5 * UI_UNIT_X, - UI_UNIT_Y, - &ctrl_ptr, - "max", - -1, - -UI_FLT_MAX, - UI_FLT_MAX, - 0, - 0, - NULL); - UI_but_number_step_size_set(but, 10); - UI_but_number_precision_set(but, 2); + uiItemR(row, &ctrl_ptr, "frame", 0, NULL, ICON_NONE); + uiItemR(row, &ctrl_ptr, "min", 0, IFACE_("Min"), ICON_NONE); + uiItemR(row, &ctrl_ptr, "max", 0, IFACE_("Max"), ICON_NONE); but = uiDefIconBut(block, UI_BTYPE_BUT, @@ -800,251 +759,211 @@ static void draw_modifier__envelope(uiLayout *layout, UI_but_func_set(but, fmod_envelope_deletepoint_cb, env, POINTER_FROM_INT(i)); UI_block_align_begin(block); } -} -/* --------------- */ + fmodifier_influence_draw(layout, ptr); +} -/* draw settings for limits modifier */ -static void draw_modifier__limits(uiLayout *layout, - ID *fcurve_owner_id, - FModifier *fcm, - short UNUSED(width)) +static void panel_register_envelope(ARegionType *region_type, + const char *id_prefix, + PanelTypePollFn poll_fn) { - uiLayout *split, *col /* , *row */ /* UNUSED */; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierLimits, fcm, &ptr); - - /* row 1: minimum */ - { - /* row = uiLayoutRow(layout, false); */ /* UNUSED */ - - /* split into 2 columns */ - split = uiLayoutSplit(layout, 0.5f, false); + PanelType *panel_type = fmodifier_panel_register( + region_type, FMODIFIER_TYPE_ENVELOPE, envelope_panel_draw, poll_fn, id_prefix); + fmodifier_subpanel_register(region_type, + "frame_range", + "", + fmodifier_frame_range_header_draw, + fmodifier_frame_range_draw, + poll_fn, + panel_type); +} - /* x-minimum */ - col = uiLayoutColumn(split, true); - uiItemR(col, &ptr, "use_min_x", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "min_x", 0, NULL, ICON_NONE); +/** \} */ - /* y-minimum*/ - col = uiLayoutColumn(split, true); - uiItemR(col, &ptr, "use_min_y", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "min_y", 0, NULL, ICON_NONE); - } +/* -------------------------------------------------------------------- */ +/** \name Limits Modifier + * \{ */ - /* row 2: maximum */ - { - /* row = uiLayoutRow(layout, false); */ /* UNUSED */ +static void limits_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col, *row, *sub; + uiLayout *layout = panel->layout; - /* split into 2 columns */ - split = uiLayoutSplit(layout, 0.5f, false); + PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL); - /* x-minimum */ - col = uiLayoutColumn(split, true); - uiItemR(col, &ptr, "use_max_x", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "max_x", 0, NULL, ICON_NONE); + uiLayoutSetPropSep(layout, true); - /* y-minimum*/ - col = uiLayoutColumn(split, true); - uiItemR(col, &ptr, "use_max_y", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "max_y", 0, NULL, ICON_NONE); - } + /* Minimums. */ + col = uiLayoutColumn(layout, false); + row = uiLayoutRowWithHeading(col, true, IFACE_("Minumum X")); + uiItemR(row, ptr, "use_min_x", 0, "", ICON_NONE); + sub = uiLayoutColumn(row, true); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min_x")); + uiItemR(sub, ptr, "min_x", 0, "", ICON_NONE); + + row = uiLayoutRowWithHeading(col, true, IFACE_("Y")); + uiItemR(row, ptr, "use_min_y", 0, "", ICON_NONE); + sub = uiLayoutColumn(row, true); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min_y")); + uiItemR(sub, ptr, "min_y", 0, "", ICON_NONE); + + /* Maximums. */ + col = uiLayoutColumn(layout, false); + row = uiLayoutRowWithHeading(col, true, IFACE_("Maximum X")); + uiItemR(row, ptr, "use_max_x", 0, "", ICON_NONE); + sub = uiLayoutColumn(row, true); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max_x")); + uiItemR(sub, ptr, "max_x", 0, "", ICON_NONE); + + row = uiLayoutRowWithHeading(col, true, IFACE_("Y")); + uiItemR(row, ptr, "use_max_y", 0, "", ICON_NONE); + sub = uiLayoutColumn(row, true); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max_y")); + uiItemR(sub, ptr, "max_y", 0, "", ICON_NONE); + + fmodifier_influence_draw(layout, ptr); } -/* --------------- */ - -/* draw settings for stepped interpolation modifier */ -static void draw_modifier__stepped(uiLayout *layout, - ID *fcurve_owner_id, - FModifier *fcm, - short UNUSED(width)) +static void panel_register_limits(ARegionType *region_type, + const char *id_prefix, + PanelTypePollFn poll_fn) { - uiLayout *col, *sub; - PointerRNA ptr; + PanelType *panel_type = fmodifier_panel_register( + region_type, FMODIFIER_TYPE_LIMITS, limits_panel_draw, poll_fn, id_prefix); + fmodifier_subpanel_register(region_type, + "frame_range", + "", + fmodifier_frame_range_header_draw, + fmodifier_frame_range_draw, + poll_fn, + panel_type); +} - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierStepped, fcm, &ptr); +/** \} */ - /* block 1: "stepping" settings */ - col = uiLayoutColumn(layout, false); - uiItemR(col, &ptr, "frame_step", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "frame_offset", 0, NULL, ICON_NONE); +/* -------------------------------------------------------------------- */ +/** \name Stepped Interpolation Modifier + * \{ */ - /* block 2: start range settings */ - col = uiLayoutColumn(layout, true); - uiItemR(col, &ptr, "use_frame_start", 0, NULL, ICON_NONE); +static void stepped_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *col, *sub, *row; + uiLayout *layout = panel->layout; - sub = uiLayoutColumn(col, true); - uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_start")); - uiItemR(sub, &ptr, "frame_start", 0, NULL, ICON_NONE); + PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL); - /* block 3: end range settings */ - col = uiLayoutColumn(layout, true); - uiItemR(col, &ptr, "use_frame_end", 0, NULL, ICON_NONE); + uiLayoutSetPropSep(layout, true); - sub = uiLayoutColumn(col, true); - uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_end")); - uiItemR(sub, &ptr, "frame_end", 0, NULL, ICON_NONE); + /* Stepping Settings. */ + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "frame_step", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "frame_offset", 0, NULL, ICON_NONE); + + /* Start range settings. */ + row = uiLayoutRowWithHeading(layout, true, IFACE_("Start Frame")); + uiItemR(row, ptr, "use_frame_start", 0, "", ICON_NONE); + sub = uiLayoutColumn(row, true); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_frame_start")); + uiItemR(sub, ptr, "frame_start", 0, "", ICON_NONE); + + /* End range settings. */ + row = uiLayoutRowWithHeading(layout, true, IFACE_("End Frame")); + uiItemR(row, ptr, "use_frame_end", 0, "", ICON_NONE); + sub = uiLayoutColumn(row, true); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_frame_end")); + uiItemR(sub, ptr, "frame_end", 0, "", ICON_NONE); + + fmodifier_influence_draw(layout, ptr); } -/* --------------- */ - -void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, - ID *fcurve_owner_id, - ListBase *modifiers, - FModifier *fcm) +static void panel_register_stepped(ARegionType *region_type, + const char *id_prefix, + PanelTypePollFn poll_fn) { - const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); - uiLayout *box, *row, *sub, *col; - uiBlock *block; - uiBut *but; - short width = 314; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifier, fcm, &ptr); + PanelType *panel_type = fmodifier_panel_register( + region_type, FMODIFIER_TYPE_STEPPED, stepped_panel_draw, poll_fn, id_prefix); + fmodifier_subpanel_register(region_type, + "frame_range", + "", + fmodifier_frame_range_header_draw, + fmodifier_frame_range_draw, + poll_fn, + panel_type); +} - /* draw header */ - { - /* get layout-row + UI-block for this */ - box = uiLayoutBox(layout); +/** \} */ - row = uiLayoutRow(box, false); - block = uiLayoutGetBlock(row); /* err... */ +/* -------------------------------------------------------------------- */ +/** \name Panel Creation + * + * \{ */ - /* left-align -------------------------------------------- */ - sub = uiLayoutRow(row, true); - uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); +/** + * Checks if the panels match the active strip / curve, rebubilds them if they don't. + */ +void ANIM_fmodifier_panels(const bContext *C, + ID *owner_id, + ListBase *fmodifiers, + uiListPanelIDFromDataFunc panel_id_fn) +{ + ARegion *region = CTX_wm_region(C); - UI_block_emboss_set(block, UI_EMBOSS_NONE); + bool panels_match = UI_panel_list_matches_data(region, fmodifiers, panel_id_fn); - /* expand */ - uiItemR(sub, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + if (!panels_match) { + UI_panels_free_instanced(C, region); + FModifier *fcm = fmodifiers->first; + for (int i = 0; fcm; i++, fcm = fcm->next) { + char panel_idname[MAX_NAME]; + panel_id_fn(fcm, panel_idname); - /* checkbox for 'active' status (for now) */ - uiItemR(sub, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + PointerRNA *fcm_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata"); + RNA_pointer_create(owner_id, &RNA_FModifier, fcm, fcm_ptr); - /* name */ - if (fmi) { - uiItemL(sub, IFACE_(fmi->name), ICON_NONE); - } - else { - uiItemL(sub, IFACE_("<Unknown Modifier>"), ICON_NONE); + UI_panel_add_instanced(C, region, ®ion->panels, panel_idname, fcm_ptr); } - - /* right-align ------------------------------------------- */ - sub = uiLayoutRow(row, true); - uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); - - /* 'mute' button */ - uiItemR(sub, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - - UI_block_emboss_set(block, UI_EMBOSS_NONE); - - /* delete button */ - but = uiDefIconBut(block, - UI_BTYPE_BUT, - B_REDR, - ICON_X, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - TIP_("Delete F-Curve Modifier")); - FModifierDeleteContext *ctx = MEM_mallocN(sizeof(FModifierDeleteContext), "fmodifier ctx"); - ctx->fcurve_owner_id = fcurve_owner_id; - ctx->modifiers = modifiers; - UI_but_funcN_set(but, delete_fmodifier_cb, ctx, fcm); - - UI_block_emboss_set(block, UI_EMBOSS); } - - /* when modifier is expanded, draw settings */ - if (fcm->flag & FMODIFIER_FLAG_EXPANDED) { - /* set up the flexible-box layout which acts as the backdrop for the modifier settings */ - box = uiLayoutBox(layout); - - /* draw settings for individual modifiers */ - switch (fcm->type) { - case FMODIFIER_TYPE_GENERATOR: /* Generator */ - draw_modifier__generator(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */ - draw_modifier__fn_generator(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_CYCLES: /* Cycles */ - draw_modifier__cycles(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_ENVELOPE: /* Envelope */ - draw_modifier__envelope(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_LIMITS: /* Limits */ - draw_modifier__limits(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_NOISE: /* Noise */ - draw_modifier__noise(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_STEPPED: /* Stepped */ - draw_modifier__stepped(box, fcurve_owner_id, fcm, width); - break; - - default: /* unknown type */ - break; - } - - /* one last panel below this: FModifier range */ - /* TODO: experiment with placement of this */ - { - box = uiLayoutBox(layout); - - /* restricted range ----------------------------------------------------- */ - col = uiLayoutColumn(box, true); - - /* top row: use restricted range */ - row = uiLayoutRow(col, true); - uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE); - - if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) { - /* second row: settings */ - row = uiLayoutRow(col, true); - - uiItemR(row, &ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE); - uiItemR(row, &ptr, "frame_end", 0, IFACE_("End"), ICON_NONE); - - /* third row: blending influence */ - row = uiLayoutRow(col, true); - - uiItemR(row, &ptr, "blend_in", 0, IFACE_("In"), ICON_NONE); - uiItemR(row, &ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE); + else { + /* Assuming there's only one group of instanced panels, update the custom data pointers. */ + Panel *panel = region->panels.first; + LISTBASE_FOREACH (FModifier *, fcm, fmodifiers) { + + /* Move to the next instanced panel corresponding to the next modifier. */ + while ((panel->type == NULL) || !(panel->type->flag & PANEL_TYPE_INSTANCED)) { + panel = panel->next; + BLI_assert(panel != NULL); /* There shouldn't be fewer panels than modifiers with UIs. */ } - /* influence -------------------------------------------------------------- */ - col = uiLayoutColumn(box, true); - - /* top row: use influence */ - uiItemR(col, &ptr, "use_influence", 0, NULL, ICON_NONE); + PointerRNA *fcm_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata"); + RNA_pointer_create(owner_id, &RNA_FModifier, fcm, fcm_ptr); + UI_panel_custom_data_set(panel, fcm_ptr); - if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE) { - /* second row: influence value */ - uiItemR(col, &ptr, "influence", 0, NULL, ICON_NONE); - } + panel = panel->next; } } } +void ANIM_modifier_panels_register_graph_and_NLA(ARegionType *region_type, + const char *modifier_panel_prefix, + PanelTypePollFn poll_function) +{ + panel_register_generator(region_type, modifier_panel_prefix, poll_function); + panel_register_fn_generator(region_type, modifier_panel_prefix, poll_function); + panel_register_noise(region_type, modifier_panel_prefix, poll_function); + panel_register_envelope(region_type, modifier_panel_prefix, poll_function); + panel_register_limits(region_type, modifier_panel_prefix, poll_function); + panel_register_stepped(region_type, modifier_panel_prefix, poll_function); +} + +void ANIM_modifier_panels_register_graph_only(ARegionType *region_type, + const char *modifier_panel_prefix, + PanelTypePollFn poll_function) +{ + panel_register_cycles(region_type, modifier_panel_prefix, poll_function); +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Copy / Paste Buffer Code * |