UI: Add shortcuts for modifier panels

The shortcuts act on the modifier with its panel under the mouse.
The following shortcuts are enabled by default:
  - Remove modifier: X, Delete
  - Apply modifier: Ctrl A
  - Duplicate modifier: Shift D
More shortcuts can be added in the keymap.

Each panel can now store a custom data RNA pointer, and a new
function is added to get the custom data for the panel under the
cursor. This custom data could be used to refactor the "List Panel
System" to generalize it and integrate it further with RNA.

The same functionality will be added  in further commits where it
applies to constraints, grease pencil modifiers, and effects.

Differential Revision: https://developer.blender.org/D8031
This commit is contained in:
Hans Goudey 2020-06-29 15:00:25 -04:00
parent 4f8a881715
commit 1fa40c9f8a
Notes: blender-bot 2023-02-14 07:39:46 +01:00
Referenced by commit 608d9b5aa1, UI: Add shortcuts for constraint panels
Referenced by commit 053e0c0af3, UI: Add shortcuts for shader effect panels
Referenced by commit 4176adaf96, Fix T78455: Failed assert when opening a viewport panel
Referenced by commit 5d2005cbb5, UI: Add shortcuts for grease pencil modifier panels
Referenced by issue #85716, Ctrl+A apply modifier does not show more important info message
Referenced by issue #78326, Add shortcuts for modifier panels
12 changed files with 250 additions and 71 deletions

View File

@ -728,6 +728,11 @@ def km_property_editor(_params):
{"properties": [("direction", 'PREV'), ], },),
("screen.space_context_cycle", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("direction", 'NEXT'), ], },),
# Modifier panels
("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),
("object.modifier_apply", {"type": 'A', "value": 'PRESS', "ctrl": True}, {"properties": [("report", True)]}),
])
return keymap

View File

@ -393,6 +393,7 @@ static void panel_list_copy(ListBase *newlb, const ListBase *lb)
Panel *panel = lb->first;
for (; new_panel; new_panel = new_panel->next, panel = panel->next) {
new_panel->activedata = NULL;
new_panel->runtime.custom_data_ptr = NULL;
panel_list_copy(&new_panel->children, &panel->children);
}
}
@ -575,18 +576,25 @@ void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *)
region_free_gizmomap_callback = callback;
}
void BKE_area_region_panels_free(ListBase *lb)
static void area_region_panels_free_recursive(Panel *panel)
{
Panel *panel, *panel_next;
for (panel = lb->first; panel; panel = panel_next) {
panel_next = panel->next;
if (panel->activedata) {
MEM_freeN(panel->activedata);
}
BKE_area_region_panels_free(&panel->children);
MEM_SAFE_FREE(panel->activedata);
LISTBASE_FOREACH_MUTABLE (Panel *, child_panel, &panel->children) {
area_region_panels_free_recursive(child_panel);
}
BLI_freelistN(lb);
MEM_freeN(panel);
}
void BKE_area_region_panels_free(ListBase *lb)
{
LISTBASE_FOREACH_MUTABLE (Panel *, panel, lb) {
/* Free custom data just for parent panels to avoid a double free. */
MEM_SAFE_FREE(panel->runtime.custom_data_ptr);
area_region_panels_free_recursive(panel);
}
BLI_listbase_clear(lb);
}
/* not region itself */

View File

@ -7015,6 +7015,7 @@ static void direct_link_panel_list(BlendDataReader *reader, ListBase *lb)
panel->runtime_flag = 0;
panel->activedata = NULL;
panel->type = NULL;
panel->runtime.custom_data_ptr = NULL;
direct_link_panel_list(reader, &panel->children);
}
}

View File

@ -1706,12 +1706,17 @@ void UI_panel_category_draw_all(struct ARegion *region, const char *category_id_
struct PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname);
struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContext *C,
const struct wmEvent *event);
void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data);
/* Polyinstantiated panels for representing a list of data. */
struct Panel *UI_panel_add_instanced(struct ScrArea *area,
struct ARegion *region,
struct ListBase *panels,
char *panel_idname,
int list_index);
int list_index,
struct PointerRNA *custom_data);
void UI_panels_free_instanced(struct bContext *C, struct ARegion *region);
#define LIST_PANEL_UNIQUE_STR_LEN 4

View File

@ -5576,6 +5576,7 @@ static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout,
panel->layout = layout;
pt->draw(C, panel);
panel->layout = NULL;
BLI_assert(panel->runtime.custom_data_ptr = NULL);
MEM_freeN(panel);

View File

@ -245,20 +245,25 @@ static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_
/********* Functions for instanced panels. ***********/
static Panel *UI_panel_add_instanced_ex(
ScrArea *area, ARegion *region, ListBase *panels, PanelType *panel_type, int list_index)
static Panel *UI_panel_add_instanced_ex(ScrArea *area,
ARegion *region,
ListBase *panels,
PanelType *panel_type,
int list_index,
PointerRNA *custom_data)
{
Panel *panel = MEM_callocN(sizeof(Panel), "instanced panel");
panel->type = panel_type;
BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname));
panel->runtime.list_index = list_index;
panel->runtime.custom_data_ptr = custom_data;
/* Add the panel's children too. Although they aren't instanced panels, we can still use this
* function to create them, as UI_panel_begin does other things we don't need to do. */
LISTBASE_FOREACH (LinkData *, child, &panel_type->children) {
PanelType *child_type = child->data;
UI_panel_add_instanced_ex(area, region, &panel->children, child_type, list_index);
UI_panel_add_instanced_ex(area, region, &panel->children, child_type, list_index, custom_data);
}
/* Make sure the panel is added to the end of the display-order as well. This is needed for
@ -283,8 +288,12 @@ static Panel *UI_panel_add_instanced_ex(
* Called in situations where panels need to be added dynamically rather than having only one panel
* corresponding to each PanelType.
*/
Panel *UI_panel_add_instanced(
ScrArea *area, ARegion *region, ListBase *panels, char *panel_idname, int list_index)
Panel *UI_panel_add_instanced(ScrArea *area,
ARegion *region,
ListBase *panels,
char *panel_idname,
int list_index,
PointerRNA *custom_data)
{
ARegionType *region_type = region->type;
@ -296,7 +305,7 @@ Panel *UI_panel_add_instanced(
return NULL;
}
return UI_panel_add_instanced_ex(area, region, panels, panel_type, list_index);
return UI_panel_add_instanced_ex(area, region, panels, panel_type, list_index, custom_data);
}
/**
@ -332,7 +341,8 @@ static void panel_free_block(ARegion *region, Panel *panel)
}
/**
* Free a panel and it's children.
* Free a panel and it's children. Custom data is shared by the panel and its children
* and is freed by #UI_panels_free_instanced.
*
* \note The only panels that should need to be deleted at runtime are panels with the
* #PNL_INSTANCED flag set.
@ -369,6 +379,13 @@ void UI_panels_free_instanced(bContext *C, ARegion *region)
if (C != NULL && panel->activedata != NULL) {
panel_activate_state(C, panel, PANEL_STATE_EXIT);
}
/* Free panel's custom data. */
if (panel->runtime.custom_data_ptr != NULL) {
MEM_freeN(panel->runtime.custom_data_ptr);
}
/* Free the panel and its subpanels. */
panel_delete(region, &region->panels, panel);
}
}
@ -2886,6 +2903,56 @@ int ui_handler_panel_region(bContext *C,
return retval;
}
static void ui_panel_custom_data_set_recursive(Panel *panel, PointerRNA *custom_data)
{
panel->runtime.custom_data_ptr = custom_data;
LISTBASE_FOREACH (Panel *, child_panel, &panel->children) {
ui_panel_custom_data_set_recursive(child_panel, custom_data);
}
}
void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data)
{
BLI_assert(panel->type != NULL);
/* Free the old custom data, which should be shared among all of the panel's subpanels. */
if (panel->runtime.custom_data_ptr != NULL) {
MEM_freeN(panel->runtime.custom_data_ptr);
}
ui_panel_custom_data_set_recursive(panel, custom_data);
}
PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
Panel *panel = NULL;
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
panel = block->panel;
if (panel == NULL) {
continue;
}
int mx = event->x;
int my = event->y;
ui_window_to_block(region, block, &mx, &my);
int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my);
if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) {
break;
}
}
if (panel == NULL) {
return NULL;
}
PointerRNA *customdata = panel->runtime.custom_data_ptr;
return customdata;
}
/**************** window level modal panel interaction **************/
/* note, this is modal handler and should not swallow events for animation */

View File

@ -1873,14 +1873,22 @@ void uiTemplateModifiers(uiLayout *UNUSED(layout), bContext *C)
ModifierData *md = modifiers->first;
for (int i = 0; md; i++, md = md->next) {
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->panelRegister) {
char panel_idname[MAX_NAME];
modifier_panel_id(md, panel_idname);
if (mti->panelRegister == NULL) {
continue;
}
Panel *new_panel = UI_panel_add_instanced(sa, region, &region->panels, panel_idname, i);
if (new_panel != NULL) {
UI_panel_set_expand_from_list_data(C, new_panel);
}
char panel_idname[MAX_NAME];
modifier_panel_id(md, panel_idname);
/* Create custom data RNA pointer. */
PointerRNA *md_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata");
RNA_pointer_create(&ob->id, &RNA_Modifier, md, md_ptr);
Panel *new_panel = UI_panel_add_instanced(
sa, region, &region->panels, panel_idname, i, md_ptr);
if (new_panel != NULL) {
UI_panel_set_expand_from_list_data(C, new_panel);
}
}
}
@ -1890,6 +1898,27 @@ void uiTemplateModifiers(uiLayout *UNUSED(layout), bContext *C)
if ((panel->type != NULL) && (panel->type->flag & PNL_INSTANCED))
UI_panel_set_expand_from_list_data(C, panel);
}
/* Assuming there's only one group of instanced panels, update the custom data pointers. */
Panel *panel = region->panels.first;
LISTBASE_FOREACH (ModifierData *, md, modifiers) {
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->panelRegister == NULL) {
continue;
}
/* Move to the next instanced panel corresponding to the next modifier. */
while ((panel->type == NULL) || !(panel->type->flag & PNL_INSTANCED)) {
panel = panel->next;
BLI_assert(panel != NULL); /* There shouldn't be fewer panels than modifiers with UIs. */
}
PointerRNA *md_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata");
RNA_pointer_create(&ob->id, &RNA_Modifier, md, md_ptr);
UI_panel_custom_data_set(panel, md_ptr);
panel = panel->next;
}
}
}
@ -2026,9 +2055,11 @@ void uiTemplateConstraints(uiLayout *UNUSED(layout), bContext *C, bool use_bone_
char panel_idname[MAX_NAME];
panel_id_func(con, panel_idname);
Panel *new_panel = UI_panel_add_instanced(sa, region, &region->panels, panel_idname, i);
Panel *new_panel = UI_panel_add_instanced(
sa, region, &region->panels, panel_idname, i, NULL);
if (new_panel) {
/* Set the list panel functionality function pointers since we don't do it with python. */
/* Set the list panel functionality function pointers since we don't do it with
* python. */
new_panel->type->set_list_data_expand_flag = set_constraint_expand_flag;
new_panel->type->get_list_data_expand_flag = get_constraint_expand_flag;
new_panel->type->reorder = constraint_reorder;
@ -2082,7 +2113,8 @@ void uiTemplateGpencilModifiers(uiLayout *UNUSED(layout), bContext *C)
char panel_idname[MAX_NAME];
gpencil_modifier_panel_id(md, panel_idname);
Panel *new_panel = UI_panel_add_instanced(sa, region, &region->panels, panel_idname, i);
Panel *new_panel = UI_panel_add_instanced(
sa, region, &region->panels, panel_idname, i, NULL);
if (new_panel != NULL) {
UI_panel_set_expand_from_list_data(C, new_panel);
}
@ -2107,7 +2139,8 @@ void uiTemplateGpencilModifiers(uiLayout *UNUSED(layout), bContext *C)
/* -------------------------------------------------------------------- */
/** \name ShaderFx Template
*
* Template for building the panel layout for the active object's grease pencil shader effects.
* Template for building the panel layout for the active object's grease pencil shader
* effects.
* \{ */
/**
@ -2138,7 +2171,8 @@ void uiTemplateShaderFx(uiLayout *UNUSED(layout), bContext *C)
char panel_idname[MAX_NAME];
shaderfx_panel_id(fx, panel_idname);
Panel *new_panel = UI_panel_add_instanced(sa, region, &region->panels, panel_idname, i);
Panel *new_panel = UI_panel_add_instanced(
sa, region, &region->panels, panel_idname, i, NULL);
if (new_panel != NULL) {
UI_panel_set_expand_from_list_data(C, new_panel);
}

View File

@ -854,7 +854,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return datalayout_transfer_exec(C, op);
}
else {

View File

@ -153,7 +153,9 @@ bool edit_modifier_poll_generic(struct bContext *C,
const bool is_editmode_allowed);
bool edit_modifier_poll(struct bContext *C);
void edit_modifier_properties(struct wmOperatorType *ot);
int edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op);
int edit_modifier_invoke_properties(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
struct ModifierData *edit_modifier_property_get(struct wmOperator *op,
struct Object *ob,
int type);

View File

@ -88,6 +88,8 @@
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "UI_interface.h"
#include "WM_api.h"
#include "WM_types.h"
@ -1037,19 +1039,38 @@ void edit_modifier_properties(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
int edit_modifier_invoke_properties(bContext *C, wmOperator *op)
static void edit_modifier_report_property(wmOperatorType *ot)
{
ModifierData *md;
PropertyRNA *prop = RNA_def_boolean(
ot->srna, "report", false, "Report", "Create a notification after the operation");
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.
*/
int edit_modifier_invoke_properties(bContext *C, wmOperator *op, const wmEvent *event)
{
PointerRNA ctx_ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_Modifier);
if (RNA_struct_property_is_set(op->ptr, "modifier")) {
return true;
}
else {
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_Modifier);
if (ptr.data) {
md = ptr.data;
RNA_string_set(op->ptr, "modifier", md->name);
return true;
else if (ctx_ptr.data != NULL) {
ModifierData *md = ctx_ptr.data;
RNA_string_set(op->ptr, "modifier", md->name);
return true;
}
else 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;
}
}
}
@ -1085,6 +1106,10 @@ static int modifier_remove_exec(bContext *C, wmOperator *op)
ModifierData *md = edit_modifier_property_get(op, ob, 0);
int mode_orig = ob->mode;
/* Store name temporarily for report. */
char name[MAX_NAME];
strcpy(name, md->name);
if (!md || !ED_object_modifier_remove(op->reports, bmain, ob, md)) {
return OPERATOR_CANCELLED;
}
@ -1099,12 +1124,17 @@ static int modifier_remove_exec(bContext *C, wmOperator *op)
}
}
}
if (RNA_boolean_get(op->ptr, "report")) {
BKE_reportf(op->reports, RPT_INFO, "Removed modifier: %s", name);
}
return OPERATOR_FINISHED;
}
static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static int modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (edit_modifier_invoke_properties(C, op)) {
if (edit_modifier_invoke_properties(C, op, event)) {
return modifier_remove_exec(C, op);
}
else {
@ -1125,6 +1155,7 @@ void OBJECT_OT_modifier_remove(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
edit_modifier_report_property(ot);
}
/** \} */
@ -1148,9 +1179,9 @@ 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 *UNUSED(event))
static int modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (edit_modifier_invoke_properties(C, op)) {
if (edit_modifier_invoke_properties(C, op, event)) {
return modifier_move_up_exec(C, op);
}
else {
@ -1194,9 +1225,9 @@ 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 *UNUSED(event))
static int modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (edit_modifier_invoke_properties(C, op)) {
if (edit_modifier_invoke_properties(C, op, event)) {
return modifier_move_down_exec(C, op);
}
else {
@ -1246,9 +1277,9 @@ 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 *UNUSED(event))
static int modifier_move_to_index_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (edit_modifier_invoke_properties(C, op)) {
if (edit_modifier_invoke_properties(C, op, event)) {
return modifier_move_to_index_exec(C, op);
}
else {
@ -1315,6 +1346,10 @@ static int modifier_apply_exec(bContext *C, wmOperator *op)
ModifierData *md = edit_modifier_property_get(op, ob, 0);
int apply_as = RNA_enum_get(op->ptr, "apply_as");
/* Store name temporarily for report. */
char name[MAX_NAME];
strcpy(name, md->name);
if (!md || !ED_object_modifier_apply(bmain, op->reports, depsgraph, scene, ob, md, apply_as)) {
return OPERATOR_CANCELLED;
}
@ -1323,12 +1358,16 @@ static int modifier_apply_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
if (RNA_boolean_get(op->ptr, "report")) {
BKE_reportf(op->reports, RPT_INFO, "Applied modifier: %s", name);
}
return OPERATOR_FINISHED;
}
static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (edit_modifier_invoke_properties(C, op)) {
if (edit_modifier_invoke_properties(C, op, event)) {
return modifier_apply_exec(C, op);
}
else {
@ -1366,6 +1405,7 @@ void OBJECT_OT_modifier_apply(wmOperatorType *ot)
"Apply as",
"How to apply the modifier to the geometry");
edit_modifier_properties(ot);
edit_modifier_report_property(ot);
}
/** \} */
@ -1396,7 +1436,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return modifier_convert_exec(C, op);
}
else {
@ -1440,9 +1480,9 @@ static int modifier_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static int modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (edit_modifier_invoke_properties(C, op)) {
if (edit_modifier_invoke_properties(C, op, event)) {
return modifier_copy_exec(C, op);
}
else {
@ -1501,7 +1541,7 @@ static int multires_higher_levels_delete_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return multires_higher_levels_delete_exec(C, op);
}
else {
@ -1579,7 +1619,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return multires_subdivide_exec(C, op);
}
else {
@ -1656,7 +1696,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return multires_reshape_exec(C, op);
}
else {
@ -1720,7 +1760,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)) {
if (!edit_modifier_invoke_properties(C, op, NULL)) {
return OPERATOR_CANCELLED;
}
@ -1835,9 +1875,9 @@ static int multires_base_apply_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static int multires_base_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static int multires_base_apply_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (edit_modifier_invoke_properties(C, op)) {
if (edit_modifier_invoke_properties(C, op, event)) {
return multires_base_apply_exec(C, op);
}
else {
@ -1891,7 +1931,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return multires_unsubdivide_exec(C, op);
}
else {
@ -1949,7 +1989,7 @@ static int multires_rebuild_subdiv_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return multires_rebuild_subdiv_exec(C, op);
}
else {
@ -2327,7 +2367,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return skin_armature_create_exec(C, op);
}
else {
@ -2406,7 +2446,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return correctivesmooth_bind_exec(C, op);
}
else {
@ -2483,7 +2523,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return meshdeform_bind_exec(C, op);
}
else {
@ -2539,7 +2579,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return explode_refresh_exec(C, op);
}
else {
@ -2743,7 +2783,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return ocean_bake_exec(C, op);
}
else {
@ -2822,7 +2862,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return laplaciandeform_bind_exec(C, op);
}
else {
@ -2891,7 +2931,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)) {
if (edit_modifier_invoke_properties(C, op, NULL)) {
return surfacedeform_bind_exec(C, op);
}
else {

View File

@ -41,6 +41,7 @@ struct uiLayout;
struct wmDrawBuffer;
struct wmTimer;
struct wmTooltipState;
struct PointerRNA;
/* TODO Doing this is quite ugly :)
* Once the top-bar is merged bScreen should be refactored to use ScrAreaMap. */
@ -135,6 +136,15 @@ typedef struct Panel_Runtime {
/* For instanced panels: Index of the list item the panel corresponds to. */
int list_index;
/**
* Pointer for storing which data the panel corresponds to.
* Useful when there can be multiple instances of the same panel type.
*
* \note A panel and its subpanels share the same custom data pointer.
* This avoids freeing the same pointer twice when panels are removed.
*/
struct PointerRNA *custom_data_ptr;
} Panel_Runtime;
/** The part from uiBlock that needs saved in file. */

View File

@ -236,12 +236,15 @@ static void modifier_ops_extra_draw(bContext *C, uiLayout *layout, void *md_v)
uiLayoutSetUnitsX(layout, 4.0f);
/* Apply. */
uiItemEnumO(layout,
uiItemFullO(layout,
"OBJECT_OT_modifier_apply",
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"),
ICON_CHECKMARK,
"apply_as",
MODIFIER_APPLY_DATA);
NULL,
WM_OP_INVOKE_DEFAULT,
0,
&op_ptr);
RNA_boolean_set(&op_ptr, "report", true);
/* Apply as shapekey. */
if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) {
@ -371,7 +374,10 @@ static void modifier_panel_header(const bContext *C, Panel *panel)
if (modifier_can_delete(md) && !modifier_is_simulation(md)) {
sub = uiLayoutRow(row, false);
uiLayoutSetEmboss(sub, UI_EMBOSS_NONE);
uiItemO(sub, "", ICON_X, "OBJECT_OT_modifier_remove");
PointerRNA op_ptr;
uiItemFullO(
sub, "OBJECT_OT_modifier_remove", "", ICON_X, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_boolean_set(&op_ptr, "report", true);
buttons_number++;
}