diff options
24 files changed, 474 insertions, 134 deletions
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 20755fcf856..8171b9ce1a4 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -742,6 +742,7 @@ def km_property_editor(_params): ("buttons.start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None), ("buttons.clear_filter", {"type": 'F', "value": 'PRESS', "alt": True}, None), # Modifier panels + ("object.modifier_set_active", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), ("object.modifier_remove", {"type": 'X', "value": 'PRESS'}, {"properties": [("report", True)]}), ("object.modifier_remove", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("report", True)]}), ("object.modifier_copy", {"type": 'D', "value": 'PRESS', "shift": True}, None), diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 2491f0953c0..b0a7d89e3d8 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -407,6 +407,7 @@ struct ModifierData *BKE_modifier_new(int type); void BKE_modifier_free_ex(struct ModifierData *md, const int flag); void BKE_modifier_free(struct ModifierData *md); +void BKE_modifier_remove_from_list(struct Object *ob, struct ModifierData *md); /* Generate new UUID for the given modifier. */ void BKE_modifier_session_uuid_generate(struct ModifierData *md); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 28c912a4c9a..a620d9af946 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -77,6 +77,10 @@ bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md); bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type); +/* Active modifier. */ +void BKE_object_modifier_set_active(struct Object *ob, struct ModifierData *md); +struct ModifierData *BKE_object_active_modifier(const struct Object *ob); + bool BKE_object_copy_modifier(struct Object *ob_dst, const struct Object *ob_src, struct ModifierData *md); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 68c341692c2..dea9884f508 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -251,6 +251,11 @@ typedef struct PanelType { /* draw entirely, view changes should be handled here */ void (*draw)(const struct bContext *C, struct Panel *panel); + /** + * Identifier of a boolean property of the panel custom data. Used to draw a highlighted border. + */ + const char *active_property; + /* For instanced panels corresponding to a list: */ /** Reorder function, called when drag and drop finishes. */ diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 73ca490c395..1bdc2a5dfd2 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -4559,7 +4559,7 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ if (psys->part->type == particle_type) { /* clear modifier */ pfmd = psys_get_modifier(ob, psys); - BLI_remlink(&ob->modifiers, (ModifierData *)pfmd); + BKE_modifier_remove_from_list(ob, (ModifierData *)pfmd); BKE_modifier_free((ModifierData *)pfmd); /* clear particle system */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 3c8b685a0e0..c9bdaecfa2a 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -212,6 +212,26 @@ void BKE_modifier_free(ModifierData *md) BKE_modifier_free_ex(md, 0); } +/** + * Use instead of `BLI_remlink` when the object's active modifier should change. + */ +void BKE_modifier_remove_from_list(Object *ob, ModifierData *md) +{ + BLI_assert(BLI_findindex(&ob->modifiers, md) != -1); + + if (md->flag & eModifierFlag_Active) { + /* Prefer the previous modifier but use the next if this modifier is the first in the list. */ + if (md->next != NULL) { + BKE_object_modifier_set_active(ob, md->next); + } + else if (md->prev != NULL) { + BKE_object_modifier_set_active(ob, md->prev); + } + } + + BLI_remlink(&ob->modifiers, md); +} + void BKE_modifier_session_uuid_generate(ModifierData *md) { md->session_uuid = BLI_session_uuid_generate(); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 31d2e3738f4..d747da2213e 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1274,6 +1274,46 @@ void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData } } +/** + * Set the object's active modifier. + * + * \param md: If NULL, only clear the active modifier, otherwise + * it must be in the #Object.modifiers list. + */ +void BKE_object_modifier_set_active(Object *ob, ModifierData *md) +{ + LISTBASE_FOREACH (ModifierData *, md_iter, &ob->modifiers) { + md_iter->flag &= ~eModifierFlag_Active; + } + + if (md != NULL) { + BLI_assert(BLI_findindex(&ob->modifiers, md) != -1); + md->flag |= eModifierFlag_Active; + } +} + +ModifierData *BKE_object_active_modifier(const Object *ob) +{ + /* In debug mode, check for only one active modifier. */ +#ifndef NDEBUG + int active_count = 0; + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->flag & eModifierFlag_Active) { + active_count++; + } + } + BLI_assert(ELEM(active_count, 0, 1)); +#endif + + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->flag & eModifierFlag_Active) { + return md; + } + } + + return NULL; +} + bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type) { const ModifierTypeInfo *mti; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 0b331fb88d2..d516de535f9 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -4046,7 +4046,7 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob /* Clear modifier, skip empty ones. */ psmd = psys_get_modifier(ob, psys); if (psmd) { - BLI_remlink(&ob->modifiers, psmd); + BKE_modifier_remove_from_list(ob, (ModifierData *)psmd); BKE_modifier_free((ModifierData *)psmd); } @@ -5401,7 +5401,7 @@ void BKE_particle_system_blend_read_lib(BlendLibReader *reader, else { /* particle modifier must be removed before particle system */ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - BLI_remlink(&ob->modifiers, psmd); + BKE_modifier_remove_from_list(ob, (ModifierData *)psmd); BKE_modifier_free((ModifierData *)psmd); BLI_remlink(particles, psys); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 5cfaafeec2c..d1e5bbcb536 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -45,6 +45,8 @@ #include "BKE_context.h" #include "BKE_screen.h" +#include "RNA_access.h" + #include "BLF_api.h" #include "WM_api.h" @@ -90,6 +92,8 @@ typedef enum uiPanelRuntimeFlag { * position. Unlike #PANEL_STATE_ANIMATION, this is applied to sub-panels as well. */ PANEL_IS_DRAG_DROP = (1 << 10), + /** Draw a border with the active color around the panel. */ + PANEL_ACTIVE_BORDER = (1 << 11), } uiPanelRuntimeFlag; /* The state of the mouse position relative to the panel. */ @@ -579,6 +583,22 @@ static void set_panels_list_data_expand_flag(const bContext *C, const ARegion *r /** \name Panels * \{ */ +static bool panel_use_active_highlight(const Panel *panel) +{ + /* The caller should make sure the panel is active and has a type. */ + BLI_assert(UI_panel_is_active(panel)); + BLI_assert(panel->type != NULL); + + if (panel->type->active_property) { + PointerRNA *ptr = UI_panel_custom_data_get(panel); + if (ptr != NULL && !RNA_pointer_is_null(ptr)) { + return RNA_boolean_get(ptr, panel->type->active_property); + } + } + + return false; +} + /** * Set flag state for a panel and its sub-panels. */ @@ -1062,6 +1082,40 @@ static void panel_title_color_get(const Panel *panel, } } +static void panel_draw_highlight_border(const Panel *panel, + const rcti *rect, + const rcti *header_rect) +{ + const bool draw_box_style = panel->type->flag & PANEL_TYPE_DRAW_BOX; + const bool is_subpanel = panel->type->parent != NULL; + if (is_subpanel) { + return; + } + + float radius; + if (draw_box_style) { + /* Use the theme for box widgets. */ + const uiWidgetColors *box_wcol = &UI_GetTheme()->tui.wcol_box; + UI_draw_roundbox_corner_set(UI_CNR_ALL); + radius = box_wcol->roundness * U.widget_unit; + } + else { + UI_draw_roundbox_corner_set(UI_CNR_NONE); + radius = 0.0f; + } + + /* Abuse the property search theme color for now. */ + float color[4]; + UI_GetThemeColor4fv(TH_MATCH, color); + UI_draw_roundbox_aa(false, + rect->xmin, + UI_panel_is_closed(panel) ? header_rect->ymin : rect->ymin, + rect->xmax, + header_rect->ymax, + radius, + color); +} + static void panel_draw_aligned_widgets(const uiStyle *style, const Panel *panel, const rcti *header_rect, @@ -1287,6 +1341,10 @@ void ui_draw_aligned_panel(const uiStyle *style, show_background, region_search_filter_active); } + + if (panel_use_active_highlight(panel)) { + panel_draw_highlight_border(panel, rect, &header_rect); + } } /** \} */ @@ -2392,20 +2450,13 @@ int ui_handler_panel_region(bContext *C, continue; } - /* All mouse clicks inside panels should return in break, but continue handling - * in case there is a sub-panel header at the mouse location. */ - if (event->type == LEFTMOUSE && - ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { - retval = WM_UI_HANDLER_BREAK; - } - if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { + /* All mouse clicks inside panel headers should return in break. */ + retval = WM_UI_HANDLER_BREAK; if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER, LEFTMOUSE)) { - retval = WM_UI_HANDLER_BREAK; ui_handle_panel_header(C, block, mx, event->type, event->ctrl, event->shift); } else if (event->type == RIGHTMOUSE) { - retval = WM_UI_HANDLER_BREAK; ui_popup_context_menu_for_panel(C, region, block->panel); } break; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index b550dc2665f..9c7b112855f 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -264,7 +264,7 @@ typedef struct uiWidgetType { /* converted colors for state */ uiWidgetColors wcol; - void (*state)(struct uiWidgetType *, int state, int drawflag); + void (*state)(struct uiWidgetType *, int state, int drawflag, char emboss); void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign); void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign); void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *); @@ -2541,7 +2541,7 @@ static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wco } /* copy colors from theme, and set changes in it based on state */ -static void widget_state(uiWidgetType *wt, int state, int drawflag) +static void widget_state(uiWidgetType *wt, int state, int drawflag, char emboss) { uiWidgetStateColors *wcol_state = wt->wcol_state; @@ -2591,7 +2591,7 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag) if (state & UI_BUT_REDALERT) { const uchar red[4] = {255, 0, 0}; - if (wt->draw) { + if (wt->draw && emboss != UI_EMBOSS_NONE) { color_blend_v3_v3(wt->wcol.inner, red, 0.4f); } else { @@ -2619,12 +2619,12 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag) * \{ */ /* sliders use special hack which sets 'item' as inner when drawing filling */ -static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag) +static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, char emboss) { uiWidgetStateColors *wcol_state = wt->wcol_state; /* call this for option button */ - widget_state(wt, state, drawflag); + widget_state(wt, state, drawflag, emboss); const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag); if (color_blend != NULL) { @@ -2642,7 +2642,7 @@ static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag) } /* labels use theme colors for text */ -static void widget_state_option_menu(uiWidgetType *wt, int state, int drawflag) +static void widget_state_option_menu(uiWidgetType *wt, int state, int drawflag, char emboss) { const bTheme *btheme = UI_GetTheme(); @@ -2654,24 +2654,33 @@ static void widget_state_option_menu(uiWidgetType *wt, int state, int drawflag) copy_v3_v3_uchar(wcol_menu_option.text_sel, btheme->tui.wcol_menu_back.text_sel); wt->wcol_theme = &wcol_menu_option; - widget_state(wt, state, drawflag); + widget_state(wt, state, drawflag, emboss); wt->wcol_theme = old_wcol; } -static void widget_state_nothing(uiWidgetType *wt, int UNUSED(state), int UNUSED(drawflag)) +static void widget_state_nothing(uiWidgetType *wt, + int UNUSED(state), + int UNUSED(drawflag), + char UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); } /* special case, button that calls pulldown */ -static void widget_state_pulldown(uiWidgetType *wt, int UNUSED(state), int UNUSED(drawflag)) +static void widget_state_pulldown(uiWidgetType *wt, + int UNUSED(state), + int UNUSED(drawflag), + char UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); } /* special case, pie menu items */ -static void widget_state_pie_menu_item(uiWidgetType *wt, int state, int UNUSED(drawflag)) +static void widget_state_pie_menu_item(uiWidgetType *wt, + int state, + int UNUSED(drawflag), + char UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); @@ -2703,7 +2712,10 @@ static void widget_state_pie_menu_item(uiWidgetType *wt, int state, int UNUSED(d } /* special case, menu items */ -static void widget_state_menu_item(uiWidgetType *wt, int state, int UNUSED(drawflag)) +static void widget_state_menu_item(uiWidgetType *wt, + int state, + int UNUSED(drawflag), + char UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); @@ -3872,7 +3884,8 @@ static void widget_unitvec( static void widget_icon_has_anim( uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign) { - if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) { + if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT) && + but->emboss != UI_EMBOSS_NONE) { uiWidgetBase wtb; widget_init(&wtb); wtb.draw_outline = false; @@ -4051,18 +4064,18 @@ static void widget_optionbut(uiWidgetColors *wcol, } /* labels use Editor theme colors for text */ -static void widget_state_label(uiWidgetType *wt, int state, int drawflag) +static void widget_state_label(uiWidgetType *wt, int state, int drawflag, char emboss) { if (state & UI_BUT_LIST_ITEM) { /* Override default label theme's colors. */ bTheme *btheme = UI_GetTheme(); wt->wcol_theme = &btheme->tui.wcol_list_item; /* call this for option button */ - widget_state(wt, state, drawflag); + widget_state(wt, state, drawflag, emboss); } else { /* call this for option button */ - widget_state(wt, state, drawflag); + widget_state(wt, state, drawflag, emboss); if (state & UI_SELECT) { UI_GetThemeColor3ubv(TH_TEXT_HI, wt->wcol.text); } @@ -4799,7 +4812,7 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu } #endif - wt->state(wt, state, drawflag); + wt->state(wt, state, drawflag, but->emboss); if (wt->custom) { wt->custom(but, &wt->wcol, rect, state, roundboxalign); } @@ -4844,7 +4857,7 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect) { uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK); - wt->state(wt, 0, 0); + wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED); if (block) { wt->draw(&wt->wcol, rect, block->flag, block->direction); } @@ -4865,7 +4878,7 @@ void ui_draw_box_opaque(rcti *rect, int roundboxalign) /* Alpha blend with the region's background color to force an opaque background. */ uiWidgetColors *wcol = &wt->wcol; - wt->state(wt, 0, 0); + wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED); float background[4]; UI_GetThemeColor4fv(TH_BACK, background); float new_inner[4]; @@ -4967,7 +4980,7 @@ void ui_draw_popover_back(struct ARegion *region, wt->wcol_theme, rect, block->direction, U.widget_unit / block->aspect, mval_origin); } else { - wt->state(wt, 0, 0); + wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED); wt->draw(&wt->wcol, rect, 0, 0); } @@ -5156,7 +5169,7 @@ static void ui_draw_widget_back_color(uiWidgetTypeEnum type, } rcti rect_copy = *rect; - wt->state(wt, 0, 0); + wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED); if (color) { rgba_float_to_uchar(wt->wcol.inner, color); } @@ -5175,7 +5188,7 @@ void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow) void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(block), rcti *rect) { uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP); - wt->state(wt, 0, 0); + wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED); /* wt->draw ends up using same function to draw the tooltip as menu_back */ wt->draw(&wt->wcol, rect, 0, 0); } @@ -5202,7 +5215,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, const rcti _rect = *rect; char *cpoin = NULL; - wt->state(wt, state, 0); + wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED); wt->draw(&wt->wcol, rect, 0, 0); UI_fontstyle_set(fstyle); @@ -5285,7 +5298,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, if (use_sep) { if (cpoin) { /* Set inactive state for grayed out text. */ - wt->state(wt, state | UI_BUT_INACTIVE, 0); + wt->state(wt, state | UI_BUT_INACTIVE, 0, UI_EMBOSS_UNDEFINED); rect->xmax = _rect.xmax - 5; UI_fontstyle_draw(fstyle, @@ -5309,7 +5322,7 @@ void ui_draw_preview_item( uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM); /* drawing button background */ - wt->state(wt, state, 0); + wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED); wt->draw(&wt->wcol, rect, 0, 0); /* draw icon in rect above the space reserved for the label */ diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 99989f86381..4cbb8858bf4 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -864,7 +864,7 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op) static int datalayout_transfer_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return datalayout_transfer_exec(C, op); } return WM_menu_invoke(C, op, event); diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 91c9916d227..d56ee17a73f 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -717,7 +717,7 @@ static int object_hook_remove_exec(bContext *C, wmOperator *op) /* remove functionality */ - BLI_remlink(&ob->modifiers, (ModifierData *)hmd); + BKE_modifier_remove_from_list(ob, (ModifierData *)hmd); BKE_modifier_free((ModifierData *)hmd); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index d0c6134bab5..e6ef53a3d65 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -156,10 +156,12 @@ bool edit_modifier_poll_generic(struct bContext *C, const bool is_editmode_allowed, const bool is_liboverride_allowed); void edit_modifier_properties(struct wmOperatorType *ot); -bool edit_modifier_invoke_properties(struct bContext *C, - struct wmOperator *op, - const struct wmEvent *event, - int *r_retval); +bool edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op); +bool edit_modifier_invoke_properties_with_hover_no_active(struct bContext *C, + struct wmOperator *op, + const struct wmEvent *event, + int *r_retval); + struct ModifierData *edit_modifier_property_get(struct wmOperator *op, struct Object *ob, int type); @@ -173,6 +175,7 @@ void OBJECT_OT_modifier_apply(struct wmOperatorType *ot); void OBJECT_OT_modifier_apply_as_shapekey(wmOperatorType *ot); void OBJECT_OT_modifier_convert(struct wmOperatorType *ot); void OBJECT_OT_modifier_copy(struct wmOperatorType *ot); +void OBJECT_OT_modifier_set_active(struct wmOperatorType *ot); void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot); void OBJECT_OT_multires_reshape(struct wmOperatorType *ot); void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 6bd95cd8e51..7d12fa1805b 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -36,6 +36,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_force_types.h" #include "DNA_scene_types.h" +#include "DNA_space_types.h" #include "BLI_bitmap.h" #include "BLI_listbase.h" @@ -239,6 +240,8 @@ ModifierData *ED_object_modifier_add( } } + BKE_object_modifier_set_active(ob, new_md); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); DEG_relations_tag_update(bmain); @@ -384,7 +387,7 @@ static bool object_modifier_remove( ob->mode &= ~OB_MODE_PARTICLE_EDIT; } - BLI_remlink(&ob->modifiers, md); + BKE_modifier_remove_from_list(ob, md); BKE_modifier_free(md); BKE_object_free_derived_caches(ob); @@ -444,8 +447,7 @@ bool ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *m } } - BLI_remlink(&ob->modifiers, md); - BLI_insertlinkbefore(&ob->modifiers, md->prev, md); + BLI_listbase_swaplinks(&ob->modifiers, md, md->prev); } else { BKE_report(reports, RPT_WARNING, "Cannot move modifier beyond the start of the list"); @@ -469,8 +471,7 @@ bool ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData } } - BLI_remlink(&ob->modifiers, md); - BLI_insertlinkafter(&ob->modifiers, md->next, md); + BLI_listbase_swaplinks(&ob->modifiers, md, md->next); } else { BKE_report(reports, RPT_WARNING, "Cannot move modifier beyond the end of the list"); @@ -896,7 +897,7 @@ bool ED_object_modifier_apply(Main *bmain, md_eval->mode = prev_mode; if (!keep_modifier) { - BLI_remlink(&ob->modifiers, md); + BKE_modifier_remove_from_list(ob, md); BKE_modifier_free(md); } @@ -914,6 +915,7 @@ int ED_object_modifier_copy( nmd = object_copy_particle_system(bmain, scene, ob, ((ParticleSystemModifierData *)md)->psys); BLI_remlink(&ob->modifiers, nmd); BLI_insertlinkafter(&ob->modifiers, md, nmd); + BKE_object_modifier_set_active(ob, nmd); return true; } @@ -921,6 +923,7 @@ int ED_object_modifier_copy( BKE_modifier_copydata(md, nmd); BLI_insertlinkafter(&ob->modifiers, md, nmd); BKE_modifier_unique_name(&ob->modifiers, nmd); + BKE_object_modifier_set_active(ob, nmd); nmd->flag |= eModifierFlag_OverrideLibrary_Local; @@ -1024,7 +1027,7 @@ void OBJECT_OT_modifier_add(wmOperatorType *ot) /** \} */ /* ------------------------------------------------------------------- */ -/** \name Generic Functions For Operators +/** \name Generic Poll Function and Properties * * Using modifier names and data context. * \{ */ @@ -1090,16 +1093,15 @@ static void edit_modifier_report_property(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -/** - * \param event: If this isn't NULL, the operator will also look for panels underneath - * the cursor with customdata set to a modifier. - * \param r_retval: This should be used if #event is used in order to to return - * #OPERATOR_PASS_THROUGH to check other operators with the same key set. - */ -bool edit_modifier_invoke_properties(bContext *C, - wmOperator *op, - const wmEvent *event, - int *r_retval) +/** \} */ + +/* ------------------------------------------------------------------- */ +/** \name Generic Invoke Functions + * + * Using modifier names and data context. + * \{ */ + +bool edit_modifier_invoke_properties(bContext *C, wmOperator *op) { if (RNA_struct_property_is_set(op->ptr, "modifier")) { return true; @@ -1112,27 +1114,6 @@ bool edit_modifier_invoke_properties(bContext *C, return true; } - /* Check the custom data of panels under the mouse for a modifier. */ - if (event != NULL) { - PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event); - - if (!(panel_ptr == NULL || RNA_pointer_is_null(panel_ptr))) { - if (RNA_struct_is_a(panel_ptr->type, &RNA_Modifier)) { - ModifierData *md = panel_ptr->data; - RNA_string_set(op->ptr, "modifier", md->name); - return true; - } - BLI_assert(r_retval != NULL); /* We need the return value in this case. */ - if (r_retval != NULL) { - *r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); - } - return false; - } - } - - if (r_retval != NULL) { - *r_retval = OPERATOR_CANCELLED; - } return false; } @@ -1195,13 +1176,14 @@ static int modifier_remove_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - int retval; - if (edit_modifier_invoke_properties(C, op, event, &retval)) { + if (edit_modifier_invoke_properties(C, op)) { return modifier_remove_exec(C, op); } - return retval; + + /* Work around multiple operators using the same shortcut. */ + return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); } void OBJECT_OT_modifier_remove(wmOperatorType *ot) @@ -1241,13 +1223,13 @@ static int modifier_move_up_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - int retval; - if (edit_modifier_invoke_properties(C, op, event, &retval)) { + if (edit_modifier_invoke_properties(C, op)) { return modifier_move_up_exec(C, op); } - return retval; + /* Work around multiple operators using the same shortcut. */ + return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); } void OBJECT_OT_modifier_move_up(wmOperatorType *ot) @@ -1286,13 +1268,13 @@ static int modifier_move_down_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - int retval; - if (edit_modifier_invoke_properties(C, op, event, &retval)) { + if (edit_modifier_invoke_properties(C, op)) { return modifier_move_down_exec(C, op); } - return retval; + /* Work around multiple operators using the same shortcut. */ + return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); } void OBJECT_OT_modifier_move_down(wmOperatorType *ot) @@ -1329,13 +1311,12 @@ static int modifier_move_to_index_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int modifier_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - int retval; - if (edit_modifier_invoke_properties(C, op, event, &retval)) { + if (edit_modifier_invoke_properties(C, op)) { return modifier_move_to_index_exec(C, op); } - return retval; + return OPERATOR_CANCELLED; } void OBJECT_OT_modifier_move_to_index(wmOperatorType *ot) @@ -1434,13 +1415,13 @@ static int modifier_apply_exec(bContext *C, wmOperator *op) return modifier_apply_exec_ex(C, op, MODIFIER_APPLY_DATA, false); } -static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - int retval; - if (edit_modifier_invoke_properties(C, op, event, &retval)) { + if (edit_modifier_invoke_properties(C, op)) { return modifier_apply_exec(C, op); } - return retval; + /* Work around multiple operators using the same shortcut. */ + return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); } void OBJECT_OT_modifier_apply(wmOperatorType *ot) @@ -1478,13 +1459,15 @@ static int modifier_apply_as_shapekey_exec(bContext *C, wmOperator *op) return modifier_apply_exec_ex(C, op, MODIFIER_APPLY_SHAPE, keep); } -static int modifier_apply_as_shapekey_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int modifier_apply_as_shapekey_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) { - int retval; - if (edit_modifier_invoke_properties(C, op, event, &retval)) { + if (edit_modifier_invoke_properties(C, op)) { return modifier_apply_as_shapekey_exec(C, op); } - return retval; + /* Work around multiple operators using the same shortcut. */ + return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); } static char *modifier_apply_as_shapekey_get_description(struct bContext *UNUSED(C), @@ -1546,7 +1529,7 @@ static int modifier_convert_exec(bContext *C, wmOperator *op) static int modifier_convert_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return modifier_convert_exec(C, op); } return OPERATOR_CANCELLED; @@ -1590,13 +1573,13 @@ static int modifier_copy_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - int retval; - if (edit_modifier_invoke_properties(C, op, event, &retval)) { + if (edit_modifier_invoke_properties(C, op)) { return modifier_copy_exec(C, op); } - return retval; + /* Work around multiple operators using the same shortcut. */ + return (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); } void OBJECT_OT_modifier_copy(wmOperatorType *ot) @@ -1617,6 +1600,91 @@ void OBJECT_OT_modifier_copy(wmOperatorType *ot) /** \} */ /* ------------------------------------------------------------------- */ +/** \name Set Active Modifier Operator + * \{ */ + +static int modifier_set_active_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + ModifierData *md = edit_modifier_property_get(op, ob, 0); + + /* If there is no modifier set for this operator, clear the active modifier field. */ + BKE_object_modifier_set_active(ob, md); + + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +/** + * Get the modifier below the mouse cursor modifier without checking the context pointer. + * Used in order to set the active modifier on mouse click. If this checked the context + * pointer then it would always set the active modifier to the already active modifier. + * + * \param event: If this isn't NULL, the operator will also look for panels underneath + * the cursor with customdata set to a modifier. + * \param r_retval: This should be used if #event is used in order to to return + * #OPERATOR_PASS_THROUGH to check other operators with the same key set. + */ +bool edit_modifier_invoke_properties_with_hover_no_active(bContext *C, + wmOperator *op, + const wmEvent *event, + int *r_retval) +{ + if (RNA_struct_property_is_set(op->ptr, "modifier")) { + return true; + } + + PointerRNA *panel_ptr = UI_region_panel_custom_data_under_cursor(C, event); + + if (!(panel_ptr == NULL || RNA_pointer_is_null(panel_ptr))) { + if (RNA_struct_is_a(panel_ptr->type, &RNA_Modifier)) { + ModifierData *md = panel_ptr->data; + RNA_string_set(op->ptr, "modifier", md->name); + return true; + } + BLI_assert(r_retval != NULL); /* We need the return value in this case. */ + if (r_retval != NULL) { + *r_retval = (OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED); + } + return false; + } + + if (r_retval != NULL) { + *r_retval = OPERATOR_CANCELLED; + } + + return false; +} + +static int modifier_set_active_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int retval; + if (edit_modifier_invoke_properties_with_hover_no_active(C, op, event, &retval)) { + return modifier_set_active_exec(C, op); + } + + return retval; +} + +void OBJECT_OT_modifier_set_active(wmOperatorType *ot) +{ + ot->name = "Set Active Modifier"; + ot->description = "Activate the modifier to use as the context"; + ot->idname = "OBJECT_OT_modifier_set_active"; + + ot->invoke = modifier_set_active_invoke; + ot->exec = modifier_set_active_exec; + ot->poll = edit_modifier_liboverride_allowed_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); +} + +/** \} */ + +/* ------------------------------------------------------------------- */ /** \name Multires Delete Higher Levels Operator * \{ */ @@ -1650,7 +1718,7 @@ static int multires_higher_levels_delete_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return multires_higher_levels_delete_exec(C, op); } return OPERATOR_CANCELLED; @@ -1726,7 +1794,7 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op) static int multires_subdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return multires_subdivide_exec(C, op); } return OPERATOR_CANCELLED; @@ -1801,7 +1869,7 @@ static int multires_reshape_exec(bContext *C, wmOperator *op) static int multires_reshape_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return multires_reshape_exec(C, op); } return OPERATOR_CANCELLED; @@ -1862,7 +1930,7 @@ static int multires_external_save_invoke(bContext *C, wmOperator *op, const wmEv Mesh *me = ob->data; char path[FILE_MAX]; - if (!edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (!edit_modifier_invoke_properties(C, op)) { return OPERATOR_CANCELLED; } @@ -1980,7 +2048,7 @@ static int multires_base_apply_exec(bContext *C, wmOperator *op) static int multires_base_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return multires_base_apply_exec(C, op); } return OPERATOR_CANCELLED; @@ -2032,7 +2100,7 @@ static int multires_unsubdivide_exec(bContext *C, wmOperator *op) static int multires_unsubdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return multires_unsubdivide_exec(C, op); } return OPERATOR_CANCELLED; @@ -2088,7 +2156,7 @@ static int multires_rebuild_subdiv_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return multires_rebuild_subdiv_exec(C, op); } return OPERATOR_CANCELLED; @@ -2451,7 +2519,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op) static int skin_armature_create_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return skin_armature_create_exec(C, op); } return OPERATOR_CANCELLED; @@ -2527,7 +2595,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op) static int correctivesmooth_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return correctivesmooth_bind_exec(C, op); } return OPERATOR_CANCELLED; @@ -2602,7 +2670,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op) static int meshdeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return meshdeform_bind_exec(C, op); } return OPERATOR_CANCELLED; @@ -2656,7 +2724,7 @@ static int explode_refresh_exec(bContext *C, wmOperator *op) static int explode_refresh_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return explode_refresh_exec(C, op); } return OPERATOR_CANCELLED; @@ -2857,7 +2925,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) static int ocean_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return ocean_bake_exec(C, op); } return OPERATOR_CANCELLED; @@ -2934,7 +3002,7 @@ static int laplaciandeform_bind_exec(bContext *C, wmOperator *op) static int laplaciandeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return laplaciandeform_bind_exec(C, op); } return OPERATOR_CANCELLED; @@ -3001,7 +3069,7 @@ static int surfacedeform_bind_exec(bContext *C, wmOperator *op) static int surfacedeform_bind_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (edit_modifier_invoke_properties(C, op, NULL, NULL)) { + if (edit_modifier_invoke_properties(C, op)) { return surfacedeform_bind_exec(C, op); } return OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 3fc29f3147b..8ba0ce5fd08 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -137,6 +137,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_modifier_apply_as_shapekey); WM_operatortype_append(OBJECT_OT_modifier_convert); WM_operatortype_append(OBJECT_OT_modifier_copy); + WM_operatortype_append(OBJECT_OT_modifier_set_active); WM_operatortype_append(OBJECT_OT_multires_subdivide); WM_operatortype_append(OBJECT_OT_multires_reshape); WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 29393e8a8d1..8841b1955bf 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -550,7 +550,7 @@ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par) /* free modifier if match */ if (free) { - BLI_remlink(&ob->modifiers, md); + BKE_modifier_remove_from_list(ob, md); BKE_modifier_free(md); } } diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 553782e2c0f..3a2b8cf0115 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -49,6 +49,7 @@ #include "BKE_linestyle.h" #include "BKE_material.h" #include "BKE_modifier.h" +#include "BKE_object.h" #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_screen.h" @@ -274,16 +275,22 @@ static bool buttons_context_path_modifier(ButsContextPath *path) if (buttons_context_path_object(path)) { Object *ob = path->ptr[path->len - 1].data; - if (ob && ELEM(ob->type, - OB_MESH, - OB_CURVE, - OB_FONT, - OB_SURF, - OB_LATTICE, - OB_GPENCIL, - OB_HAIR, - OB_POINTCLOUD, - OB_VOLUME)) { + if (ELEM(ob->type, + OB_MESH, + OB_CURVE, + OB_FONT, + OB_SURF, + OB_LATTICE, + OB_GPENCIL, + OB_HAIR, + OB_POINTCLOUD, + OB_VOLUME)) { + ModifierData *md = BKE_object_active_modifier(ob); + if (md != NULL) { + RNA_pointer_create(&ob->id, &RNA_Modifier, md, &path->ptr[path->len]); + path->len++; + } + return true; } } @@ -941,6 +948,17 @@ int /*eContextResult*/ buttons_context(const bContext *C, return CTX_RESULT_OK; } + if (CTX_data_equals(member, "modifier")) { + PointerRNA *ptr = get_pointer_type(path, &RNA_Modifier); + + if (ptr != NULL && !RNA_pointer_is_null(ptr)) { + Object *ob = (Object *)ptr->owner_id; + ModifierData *md = ptr->data; + CTX_data_pointer_set(result, &ob->id, &RNA_Modifier, md); + return CTX_RESULT_OK; + } + return CTX_RESULT_NO_DATA; + } if (CTX_data_equals(member, "texture_user")) { ButsContextTexture *ct = sbuts->texuser; diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 609fc43b435..baee08608ce 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -408,6 +408,14 @@ static void node_area_listener(wmWindow *UNUSED(win), ED_area_tag_refresh(area); } } + else if (ED_node_is_geometry(snode)) { + /* Rather strict check: only redraw when the reference matches the current editor's ID. */ + if (wmn->data == ND_MODIFIER) { + if (wmn->reference == snode->id || snode->id == NULL) { + ED_area_tag_refresh(area); + } + } + } break; case NC_SPACE: if (wmn->data == ND_SPACE_NODE) { diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 43ed532a65b..edb0a4439d6 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -143,6 +143,11 @@ typedef enum { eModifierFlag_OverrideLibrary_Local = (1 << 0), /* This modifier does not own its caches, but instead shares them with another modifier. */ eModifierFlag_SharedCaches = (1 << 1), + /** + * This modifier is the object's active modifier. Used for context in the node editor. + * Only one modifier on an object should have this flag set. + */ + eModifierFlag_Active = (1 << 2), } ModifierFlag; /* not a real modifier */ diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 328e4d2ba22..71f67d8a3b4 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -431,6 +431,8 @@ typedef struct ObHook { /* used many places... should be specialized */ #define SELECT 1 +#define OBJECT_ACTIVE_MODIFIER_NONE -1 + /* type */ enum { OB_EMPTY = 0, diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 09c1869b84b..30d612d2634 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -676,6 +676,23 @@ static void rna_Modifier_dependency_update(Main *bmain, Scene *scene, PointerRNA DEG_relations_tag_update(bmain); } +static void rna_Modifier_is_active_set(PointerRNA *ptr, bool value) +{ + ModifierData *md = ptr->data; + + if (value) { + /* Disable the active flag of all other modif-iers. */ + for (ModifierData *prev_md = md->prev; prev_md != NULL; prev_md = prev_md->prev) { + prev_md->flag &= ~eModifierFlag_Active; + } + for (ModifierData *next_md = md->next; next_md != NULL; next_md = next_md->next) { + next_md->flag &= ~eModifierFlag_Active; + } + + md->flag |= eModifierFlag_Active; + } +} + /* Vertex Groups */ # define RNA_MOD_VGROUP_NAME_SET(_type, _prop) \ @@ -7266,6 +7283,15 @@ void RNA_def_modifier(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + prop = RNA_def_property(srna, "is_active", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", eModifierFlag_Active); + RNA_def_property_boolean_funcs(prop, NULL, "rna_Modifier_is_active_set"); + RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_ui_text(prop, "Active", "The active modifier in the list"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + prop = RNA_def_property(srna, "use_apply_on_spline", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_ApplyOnSpline); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 6f7116bfe22..627b8a3140a 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1616,6 +1616,32 @@ static void rna_Object_modifier_clear(Object *object, bContext *C) WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object); } +static PointerRNA rna_Object_active_modifier_get(PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->owner_id; + ModifierData *md = BKE_object_active_modifier(ob); + return rna_pointer_inherit_refine(ptr, &RNA_Modifier, md); +} + +static void rna_Object_active_modifier_set(PointerRNA *ptr, PointerRNA value, ReportList *reports) +{ + Object *ob = (Object *)ptr->owner_id; + ModifierData *md = value.data; + + if (RNA_pointer_is_null(&value)) { + BKE_object_modifier_set_active(ob, NULL); + return; + } + + if (BLI_findindex(&ob->modifiers, md) == -1) { + BKE_reportf( + reports, RPT_ERROR, "Modifier \"%s\" is not in the object's modifier list", md->name); + return; + } + + BKE_object_modifier_set_active(ob, md); +} + bool rna_Object_modifiers_override_apply(Main *bmain, PointerRNA *ptr_dst, PointerRNA *ptr_src, @@ -2287,6 +2313,7 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop) FunctionRNA *func; PropertyRNA *parm; + PropertyRNA *prop; RNA_def_property_srna(cprop, "ObjectModifiers"); srna = RNA_def_struct(brna, "ObjectModifiers", NULL); @@ -2333,6 +2360,17 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "clear", "rna_Object_modifier_clear"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); RNA_def_function_ui_description(func, "Remove all modifiers from the object"); + + /* Active modifier. */ + prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "Modifier"); + RNA_def_property_pointer_funcs( + prop, "rna_Object_active_modifier_get", "rna_Object_active_modifier_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_ui_text(prop, "Active Modifier", "The active modifier in the list"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); } /* object.grease_pencil_modifiers */ diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c index 6c92ceb6fc0..166d77624e8 100644 --- a/source/blender/modifiers/intern/MOD_ui_common.c +++ b/source/blender/modifiers/intern/MOD_ui_common.c @@ -417,6 +417,7 @@ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, /* Give the panel the special flag that says it was built here and corresponds to a * modifier rather than a #PanelType. */ panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_DRAW_BOX | PANEL_TYPE_INSTANCED; + panel_type->active_property = "is_active"; panel_type->reorder = modifier_reorder; panel_type->get_list_data_expand_flag = get_modifier_expand_flag; panel_type->set_list_data_expand_flag = set_modifier_expand_flag; diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc index d4a9805f311..69f9f7fb4ed 100644 --- a/source/blender/nodes/geometry/node_geometry_tree.cc +++ b/source/blender/nodes/geometry/node_geometry_tree.cc @@ -20,16 +20,49 @@ #include "NOD_geometry.h" +#include "BKE_context.h" #include "BKE_node.h" +#include "BKE_object.h" #include "BLT_translation.h" +#include "DNA_modifier_types.h" #include "DNA_node_types.h" +#include "DNA_space_types.h" #include "RNA_access.h" bNodeTreeType *ntreeType_Geometry; +static void geometry_node_tree_get_from_context(const bContext *C, + bNodeTreeType *UNUSED(treetype), + bNodeTree **r_ntree, + ID **r_id, + ID **r_from) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + + if (ob == nullptr) { + return; + } + + const ModifierData *md = BKE_object_active_modifier(ob); + + if (md == nullptr) { + return; + } + + if (md->type == eModifierType_Nodes) { + NodesModifierData *nmd = (NodesModifierData *)md; + if (nmd->node_group != nullptr) { + *r_from = &ob->id; + *r_id = &ob->id; + *r_ntree = nmd->node_group; + } + } +} + void register_node_tree_type_geo(void) { bNodeTreeType *tt = ntreeType_Geometry = static_cast<bNodeTreeType *>( @@ -41,5 +74,7 @@ void register_node_tree_type_geo(void) strcpy(tt->ui_description, N_("Geometry nodes")); tt->rna_ext.srna = &RNA_GeometryNodeTree; + tt->get_from_context = geometry_node_tree_get_from_context; + ntreeTypeAdd(tt); } |