Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py1
-rw-r--r--source/blender/blenkernel/BKE_modifier.h1
-rw-r--r--source/blender/blenkernel/BKE_object.h4
-rw-r--r--source/blender/blenkernel/BKE_screen.h5
-rw-r--r--source/blender/blenkernel/intern/fluid.c2
-rw-r--r--source/blender/blenkernel/intern/modifier.c20
-rw-r--r--source/blender/blenkernel/intern/object.c40
-rw-r--r--source/blender/blenkernel/intern/particle.c4
-rw-r--r--source/blender/editors/interface/interface_panel.c69
-rw-r--r--source/blender/editors/interface/interface_widgets.c61
-rw-r--r--source/blender/editors/object/object_data_transfer.c2
-rw-r--r--source/blender/editors/object/object_hook.c2
-rw-r--r--source/blender/editors/object/object_intern.h11
-rw-r--r--source/blender/editors/object/object_modifier.c230
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c38
-rw-r--r--source/blender/editors/space_node/space_node.c8
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h5
-rw-r--r--source/blender/makesdna/DNA_object_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c26
-rw-r--r--source/blender/makesrna/intern/rna_object.c38
-rw-r--r--source/blender/modifiers/intern/MOD_ui_common.c1
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc35
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);
}