Geometry Nodes: active modifier + geometry nodes editor

This commit adds functions to set and get the object's active
modifier, which is stored as a flag in the ModifierData struct,
similar to constraints. This will be used to set the context in
the node editor. There are no visible changes in this commit.

Similar to how the node editor context works for materials, this commit
makes the node group displayed in the node editor depend on the active
object and its active modifier. To keep the node group from changing,
just pin the node group in the header.

* Shortcuts performed while there is an active modifier will affect
  only that modifier (the exception is the A to expand the modifiers).
* Clicking anywhere on the empty space in a modifier's panel will make it active.

These changes require some refactoring of object modifier code. First
is splitting up the modifier property invoke callback, which now needs
to be able to get the active modifier separately from the hovered
modifier for the different operators.

Second is a change to removing modifiers, where there is now a separate
function to remove a modifier from an object's list, in order to handle
changing the active.

Finally, the panel handler needs a small tweak so that this "click in panel"
event can be handled afterwards.
This commit is contained in:
Hans Goudey 2020-12-02 13:35:07 +01:00 committed by Jacques Lucke
parent fc4a853846
commit 600fb28b62
Notes: blender-bot 2023-02-14 11:42:40 +01:00
Referenced by commit 2bd0263fbf, Fix T83346: Scrolling doesn't work with mouse over panel header
Referenced by issue #89350, Color indicating animation status missing from many icon buttons (all defined with emboss=False)
Referenced by issue #86299, grease pencil layers visibility icon doesn't change to purple when a driver is added
Referenced by issue #83355, Driven or keyed states no longer visible on shapekey sliders
24 changed files with 474 additions and 134 deletions

View File

@ -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),

View File

@ -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);

View File

@ -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);

View File

@ -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. */

View File

@ -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 */

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)
@ -1616,6 +1599,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;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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) {

View File

@ -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 */

View File

@ -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,

View File

@ -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(

View File

@ -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 */

View File

@ -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;

View File

@ -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);
}