UI: Redesigned data-block selectors
The previous design is rather old and has a couple of problems: * Scalability: The current solution of adding little icon buttons next to the data-block name field doesn't scale well. It only works if there's a small number of operations. We need to be able to place more items there for better data-block management. Especially with the introduction of library overrides. * Discoverability: It's not obvious what some of the icons do. They appear and disappear, but it's not obvious why some are available at times and others not. * Unclear Status: Currently their library status (linked, indirectly linked, broken link, library override) isn't really clear. * Unusual behavior: Some of the icon buttons allow Shift or Ctrl clicking to invoke alternative behaviors. This is not a usual pattern in Blender. This patch does the following changes: * Adds a menu to the right of the name button to access all kinds of operations (create, delete, unlink, user management, library overrides, etc). * Make good use of the "disabled hint" for tooltips, to explain why buttons are disabled. The UI team wants to establish this as a good practise. * Use superimposed icons for duplicate and unlink, rather than extra buttons (uses less space, looks less distracting and is a nice + consistent design language). * Remove fake user and user count button, they are available from the menu now. * Support tooltips for superimposed icons (committed mouse hover feedback to master already). * Slightly increase size of the name button - it was already a bit small before, and the move from real buttons to superimposed icons reduces usable space for the name itself. * More clearly differentiate between duplicate and creating a new data-block. The latter is only available in the menu. * Display library status icon on the left (linked, missing library, overridden, asset) * Disables "Make Single User" button - in review we weren't sure if there are good use-cases for it, so better to see if we can remove it. Note that I do expect some aspects of this design to change still. I think some changes are problematic, but others disagreed. I will open a feedback thread on devtalk to see what others think. Differential Revision: https://developer.blender.org/D8554 Reviewed by: Bastien Montagne Design discussed and agreed on with the UI team, also see T79959.
This commit is contained in:
parent
7bee1489c1
commit
2250b5cefe
Notes:
blender-bot
2023-02-14 08:24:03 +01:00
Referenced by commit2771dfd563
, UI: Revert design changes to data-block selector for the 2.92 release Referenced by commit960a0b892c
, Fix T84101: Duplicate operator not available for some data-block selectors Referenced by issue #84587, Node editor unlinking issue with duplicate nodes Referenced by issue #84570, No "Make Single User Copy" option in ID template menu for multi-user datablocks, "Duplicate" greyed out Referenced by issue #84233, Node editor: Creating new/copy of datablock disabled in nodes Referenced by issue #84101, Shader editor: duplicating material do not work there Referenced by issue #79959, Data-block Selector Design Changes Referenced by issue #78012, UI: Search Menu Design for Linked Data-blocks
|
@ -1148,7 +1148,7 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
|
|||
split = layout.split(factor=0.65)
|
||||
|
||||
if ob:
|
||||
split.template_ID(ob, "active_material", new="material.new")
|
||||
split.template_ID(ob, "active_material", new="material.new", duplicate="material.duplicate")
|
||||
row = split.row()
|
||||
|
||||
if slot:
|
||||
|
|
|
@ -133,7 +133,7 @@ class EEVEE_MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
|
|||
row = layout.row()
|
||||
|
||||
if ob:
|
||||
row.template_ID(ob, "active_material", new="material.new")
|
||||
row.template_ID(ob, "active_material", new="material.new", duplicate="material.duplicate")
|
||||
|
||||
if slot:
|
||||
icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA'
|
||||
|
|
|
@ -51,7 +51,7 @@ class WORLD_PT_context_world(WorldButtonsPanel, Panel):
|
|||
space = context.space_data
|
||||
|
||||
if scene:
|
||||
layout.template_ID(scene, "world", new="world.new")
|
||||
layout.template_ID(scene, "world", new="world.new", duplicate="world.duplicate")
|
||||
elif world:
|
||||
layout.template_ID(space, "pin_id")
|
||||
|
||||
|
|
|
@ -248,7 +248,7 @@ class DOPESHEET_HT_editor_buttons:
|
|||
|
||||
layout.separator_spacer()
|
||||
|
||||
layout.template_ID(st, "action", new="action.new", unlink="action.unlink")
|
||||
layout.template_ID(st, "action", new="action.new", duplicate="action.duplicate_assign", unlink="action.unlink")
|
||||
|
||||
# Layer management
|
||||
if st.mode == 'GPENCIL':
|
||||
|
|
|
@ -52,10 +52,11 @@ void ED_spacedata_id_remap(struct ScrArea *area,
|
|||
struct ID *old_id,
|
||||
struct ID *new_id);
|
||||
|
||||
void ED_OT_flush_edits(struct wmOperatorType *ot);
|
||||
void ED_OT_lib_id_load_custom_preview(struct wmOperatorType *ot);
|
||||
void ED_OT_lib_id_generate_preview(struct wmOperatorType *ot);
|
||||
|
||||
void ED_operatortypes_edutils(void);
|
||||
|
||||
/* ************** XXX OLD CRUFT WARNING ************* */
|
||||
|
||||
void apply_keyb_grid(
|
||||
|
|
|
@ -76,6 +76,7 @@ struct wmWindow;
|
|||
|
||||
typedef struct uiBlock uiBlock;
|
||||
typedef struct uiBut uiBut;
|
||||
typedef struct uiButExtraOpIcon uiButExtraOpIcon;
|
||||
typedef struct uiLayout uiLayout;
|
||||
typedef struct uiPopupBlockHandle uiPopupBlockHandle;
|
||||
|
||||
|
@ -1381,13 +1382,16 @@ typedef struct uiStringInfo {
|
|||
/* Note: Expects pointers to uiStringInfo structs as parameters.
|
||||
* Will fill them with translated strings, when possible.
|
||||
* Strings in uiStringInfo must be MEM_freeN'ed by caller. */
|
||||
void UI_but_string_info_get(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0);
|
||||
void UI_but_string_info_get(struct bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, ...)
|
||||
ATTR_SENTINEL(0);
|
||||
|
||||
/* Edit i18n stuff. */
|
||||
/* Name of the main py op from i18n addon. */
|
||||
#define EDTSRC_I18N_OP_NAME "UI_OT_edittranslation"
|
||||
|
||||
/**
|
||||
* TODO This is old stuff, only used by templateID. Should be cleaned up.
|
||||
*
|
||||
* Special Buttons
|
||||
*
|
||||
* Buttons with a more specific purpose:
|
||||
|
@ -1405,14 +1409,16 @@ enum {
|
|||
UI_ID_ALONE = 1 << 4,
|
||||
UI_ID_OPEN = 1 << 3,
|
||||
UI_ID_DELETE = 1 << 5,
|
||||
UI_ID_LOCAL = 1 << 6,
|
||||
UI_ID_AUTO_NAME = 1 << 7,
|
||||
UI_ID_FAKE_USER = 1 << 8,
|
||||
UI_ID_MAKE_LOCAL = 1 << 6,
|
||||
UI_ID_LIB_OVERRIDE_ADD = 1 << 7,
|
||||
UI_ID_AUTO_NAME = 1 << 8,
|
||||
UI_ID_PIN = 1 << 9,
|
||||
UI_ID_PREVIEWS = 1 << 10,
|
||||
UI_ID_OVERRIDE = 1 << 11,
|
||||
UI_ID_LIB_OVERRIDE_REMOVE = 1 << 11,
|
||||
UI_ID_LIB_OVERRIDE_RESET = 1 << 12,
|
||||
UI_ID_FULL = UI_ID_RENAME | UI_ID_BROWSE | UI_ID_ADD_NEW | UI_ID_OPEN | UI_ID_ALONE |
|
||||
UI_ID_DELETE | UI_ID_LOCAL,
|
||||
UI_ID_DELETE | UI_ID_MAKE_LOCAL | UI_ID_LIB_OVERRIDE_ADD |
|
||||
UI_ID_LIB_OVERRIDE_REMOVE | UI_ID_LIB_OVERRIDE_RESET,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1658,10 +1664,12 @@ void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN);
|
|||
|
||||
void UI_but_func_pushed_state_set(uiBut *but, uiButPushedStateFunc func, void *arg);
|
||||
|
||||
PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
|
||||
const char *opname,
|
||||
short opcontext,
|
||||
int icon);
|
||||
struct uiButExtraOpIcon *UI_but_extra_operator_icon_add(uiBut *but,
|
||||
const char *opname,
|
||||
short opcontext,
|
||||
int icon);
|
||||
struct wmOperatorType *UI_but_extra_operator_icon_optype_get(struct uiButExtraOpIcon *extra_icon);
|
||||
PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon *extra_icon);
|
||||
|
||||
/* Autocomplete
|
||||
*
|
||||
|
@ -1963,6 +1971,7 @@ void uiTemplateID(uiLayout *layout,
|
|||
struct PointerRNA *ptr,
|
||||
const char *propname,
|
||||
const char *newop,
|
||||
const char *duplicateop,
|
||||
const char *openop,
|
||||
const char *unlinkop,
|
||||
int filter,
|
||||
|
@ -2567,6 +2576,11 @@ struct ARegion *UI_tooltip_create_from_button(struct bContext *C,
|
|||
struct ARegion *butregion,
|
||||
uiBut *but,
|
||||
bool is_label);
|
||||
struct ARegion *UI_tooltip_create_from_button_or_extra_icon(struct bContext *C,
|
||||
struct ARegion *butregion,
|
||||
uiBut *but,
|
||||
uiButExtraOpIcon *extra_icon,
|
||||
bool is_label);
|
||||
struct ARegion *UI_tooltip_create_from_gizmo(struct bContext *C, struct wmGizmo *gz);
|
||||
void UI_tooltip_free(struct bContext *C, struct bScreen *screen, struct ARegion *region);
|
||||
|
||||
|
|
|
@ -1167,16 +1167,21 @@ void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_str
|
|||
* \{ */
|
||||
|
||||
static bool ui_but_event_operator_string_from_operator(const bContext *C,
|
||||
uiBut *but,
|
||||
wmOperatorCallParams *op_call_params,
|
||||
char *buf,
|
||||
const size_t buf_len)
|
||||
{
|
||||
BLI_assert(but->optype != NULL);
|
||||
BLI_assert(op_call_params->optype != NULL);
|
||||
bool found = false;
|
||||
IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
|
||||
IDProperty *prop = (op_call_params->opptr) ? op_call_params->opptr->data : NULL;
|
||||
|
||||
if (WM_key_event_operator_string(
|
||||
C, but->optype->idname, but->opcontext, prop, true, buf, buf_len)) {
|
||||
if (WM_key_event_operator_string(C,
|
||||
op_call_params->optype->idname,
|
||||
op_call_params->opcontext,
|
||||
prop,
|
||||
true,
|
||||
buf,
|
||||
buf_len)) {
|
||||
found = true;
|
||||
}
|
||||
return found;
|
||||
|
@ -1253,15 +1258,22 @@ static bool ui_but_event_operator_string_from_panel(const bContext *C,
|
|||
return found;
|
||||
}
|
||||
|
||||
static bool ui_but_event_operator_string(const bContext *C,
|
||||
uiBut *but,
|
||||
char *buf,
|
||||
const size_t buf_len)
|
||||
static bool ui_but_event_operator_string(
|
||||
const bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, char *buf, const size_t buf_len)
|
||||
{
|
||||
bool found = false;
|
||||
wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon);
|
||||
|
||||
if (but->optype != NULL) {
|
||||
found = ui_but_event_operator_string_from_operator(C, but, buf, buf_len);
|
||||
if (extra_icon_optype) {
|
||||
found = ui_but_event_operator_string_from_operator(C, extra_icon->optype_params, buf, buf_len);
|
||||
}
|
||||
else if (but->optype != NULL) {
|
||||
found = ui_but_event_operator_string_from_operator(
|
||||
C,
|
||||
&(wmOperatorCallParams){
|
||||
.optype = but->optype, .opptr = but->opptr, .opcontext = but->opcontext},
|
||||
buf,
|
||||
buf_len);
|
||||
}
|
||||
else if (UI_but_menutype_get(but) != NULL) {
|
||||
found = ui_but_event_operator_string_from_menu(C, but, buf, buf_len);
|
||||
|
@ -1564,7 +1576,7 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) {
|
||||
if (ui_but_event_operator_string(C, but, NULL, buf, sizeof(buf))) {
|
||||
ui_but_add_shortcut(but, buf, false);
|
||||
}
|
||||
else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) {
|
||||
|
@ -1605,12 +1617,12 @@ typedef enum PredefinedExtraOpIconType {
|
|||
PREDEFINED_EXTRA_OP_ICON_EYEDROPPER,
|
||||
} PredefinedExtraOpIconType;
|
||||
|
||||
static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but,
|
||||
wmOperatorType *optype,
|
||||
short opcontext,
|
||||
int icon)
|
||||
static uiButExtraOpIcon *ui_but_extra_operator_icon_add_ptr(uiBut *but,
|
||||
wmOperatorType *optype,
|
||||
short opcontext,
|
||||
int icon)
|
||||
{
|
||||
uiButExtraOpIcon *extra_op_icon = MEM_mallocN(sizeof(*extra_op_icon), __func__);
|
||||
uiButExtraOpIcon *extra_op_icon = MEM_callocN(sizeof(*extra_op_icon), __func__);
|
||||
|
||||
extra_op_icon->icon = (BIFIconID)icon;
|
||||
extra_op_icon->optype_params = MEM_callocN(sizeof(*extra_op_icon->optype_params),
|
||||
|
@ -1625,13 +1637,15 @@ static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but,
|
|||
|
||||
BLI_addtail(&but->extra_op_icons, extra_op_icon);
|
||||
|
||||
return extra_op_icon->optype_params->opptr;
|
||||
return extra_op_icon;
|
||||
}
|
||||
|
||||
static void ui_but_extra_operator_icon_free(uiButExtraOpIcon *extra_icon)
|
||||
{
|
||||
WM_operator_properties_free(extra_icon->optype_params->opptr);
|
||||
MEM_freeN(extra_icon->optype_params->opptr);
|
||||
if (extra_icon->optype_params->opptr) {
|
||||
WM_operator_properties_free(extra_icon->optype_params->opptr);
|
||||
MEM_freeN(extra_icon->optype_params->opptr);
|
||||
}
|
||||
MEM_freeN(extra_icon->optype_params);
|
||||
MEM_freeN(extra_icon);
|
||||
}
|
||||
|
@ -1644,18 +1658,25 @@ void ui_but_extra_operator_icons_free(uiBut *but)
|
|||
BLI_listbase_clear(&but->extra_op_icons);
|
||||
}
|
||||
|
||||
PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
|
||||
const char *opname,
|
||||
short opcontext,
|
||||
int icon)
|
||||
uiButExtraOpIcon *UI_but_extra_operator_icon_add(uiBut *but,
|
||||
const char *opname,
|
||||
short opcontext,
|
||||
int icon)
|
||||
{
|
||||
wmOperatorType *optype = WM_operatortype_find(opname, false);
|
||||
|
||||
if (optype) {
|
||||
return ui_but_extra_operator_icon_add_ptr(but, optype, opcontext, icon);
|
||||
}
|
||||
BLI_assert(optype);
|
||||
return ui_but_extra_operator_icon_add_ptr(but, optype, opcontext, icon);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
PointerRNA *UI_but_extra_operator_icon_opptr_get(uiButExtraOpIcon *extra_icon)
|
||||
{
|
||||
return extra_icon->optype_params->opptr;
|
||||
}
|
||||
|
||||
wmOperatorType *UI_but_extra_operator_icon_optype_get(uiButExtraOpIcon *extra_icon)
|
||||
{
|
||||
return extra_icon ? extra_icon->optype_params->optype : NULL;
|
||||
}
|
||||
|
||||
static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but)
|
||||
|
@ -6818,7 +6839,7 @@ void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN)
|
|||
but->hold_argN = argN;
|
||||
}
|
||||
|
||||
void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
||||
void UI_but_string_info_get(bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, ...)
|
||||
{
|
||||
va_list args;
|
||||
uiStringInfo *si;
|
||||
|
@ -6827,13 +6848,19 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
|||
int totitems;
|
||||
bool free_items = false;
|
||||
|
||||
va_start(args, but);
|
||||
wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon);
|
||||
wmOperatorType *optype = extra_icon ? extra_icon_optype : but->optype;
|
||||
|
||||
/* Don't query RNA data when the extra-icon overrides the button. */
|
||||
PropertyRNA *rnaprop = extra_icon ? NULL : but->rnaprop;
|
||||
|
||||
va_start(args, extra_icon);
|
||||
while ((si = (uiStringInfo *)va_arg(args, void *))) {
|
||||
uiStringInfoType type = si->type;
|
||||
char *tmp = NULL;
|
||||
|
||||
if (type == BUT_GET_LABEL) {
|
||||
if (but->str && but->str[0]) {
|
||||
if (but->str && but->str[0] && !extra_icon) {
|
||||
const char *str_sep;
|
||||
size_t str_len;
|
||||
|
||||
|
@ -6863,16 +6890,16 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
|||
}
|
||||
|
||||
if (type == BUT_GET_RNAPROP_IDENTIFIER) {
|
||||
if (but->rnaprop) {
|
||||
tmp = BLI_strdup(RNA_property_identifier(but->rnaprop));
|
||||
if (rnaprop) {
|
||||
tmp = BLI_strdup(RNA_property_identifier(rnaprop));
|
||||
}
|
||||
}
|
||||
else if (type == BUT_GET_RNASTRUCT_IDENTIFIER) {
|
||||
if (but->rnaprop && but->rnapoin.data) {
|
||||
if (rnaprop && but->rnapoin.data) {
|
||||
tmp = BLI_strdup(RNA_struct_identifier(but->rnapoin.type));
|
||||
}
|
||||
else if (but->optype) {
|
||||
tmp = BLI_strdup(but->optype->idname);
|
||||
else if (optype) {
|
||||
tmp = BLI_strdup(optype->idname);
|
||||
}
|
||||
else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) {
|
||||
MenuType *mt = UI_but_menutype_get(but);
|
||||
|
@ -6888,23 +6915,25 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
|||
}
|
||||
}
|
||||
else if (ELEM(type, BUT_GET_RNA_LABEL, BUT_GET_RNA_TIP)) {
|
||||
if (but->rnaprop) {
|
||||
if (rnaprop) {
|
||||
if (type == BUT_GET_RNA_LABEL) {
|
||||
tmp = BLI_strdup(RNA_property_ui_name(but->rnaprop));
|
||||
tmp = BLI_strdup(RNA_property_ui_name(rnaprop));
|
||||
}
|
||||
else {
|
||||
const char *t = RNA_property_ui_description(but->rnaprop);
|
||||
const char *t = RNA_property_ui_description(rnaprop);
|
||||
if (t && t[0]) {
|
||||
tmp = BLI_strdup(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (but->optype) {
|
||||
else if (optype) {
|
||||
PointerRNA *opptr = extra_icon_optype ? UI_but_extra_operator_icon_opptr_get(extra_icon) :
|
||||
but->opptr;
|
||||
if (type == BUT_GET_RNA_LABEL) {
|
||||
tmp = BLI_strdup(WM_operatortype_name(but->optype, but->opptr));
|
||||
tmp = BLI_strdup(WM_operatortype_name(optype, opptr));
|
||||
}
|
||||
else {
|
||||
tmp = WM_operatortype_description(C, but->optype, but->opptr);
|
||||
tmp = WM_operatortype_description(C, optype, opptr);
|
||||
}
|
||||
}
|
||||
else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) {
|
||||
|
@ -6956,11 +6985,11 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
|||
}
|
||||
else if (type == BUT_GET_RNA_LABEL_CONTEXT) {
|
||||
const char *_tmp = BLT_I18NCONTEXT_DEFAULT;
|
||||
if (but->rnaprop) {
|
||||
_tmp = RNA_property_translation_context(but->rnaprop);
|
||||
if (rnaprop) {
|
||||
_tmp = RNA_property_translation_context(rnaprop);
|
||||
}
|
||||
else if (but->optype) {
|
||||
_tmp = RNA_struct_translation_context(but->optype->srna);
|
||||
else if (optype) {
|
||||
_tmp = RNA_struct_translation_context(optype->srna);
|
||||
}
|
||||
else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) {
|
||||
MenuType *mt = UI_but_menutype_get(but);
|
||||
|
@ -6979,16 +7008,16 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
|||
int value = 0;
|
||||
|
||||
/* get the enum property... */
|
||||
if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM) {
|
||||
if (rnaprop && RNA_property_type(rnaprop) == PROP_ENUM) {
|
||||
/* enum property */
|
||||
ptr = &but->rnapoin;
|
||||
prop = but->rnaprop;
|
||||
prop = rnaprop;
|
||||
value = (ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_TAB)) ? (int)but->hardmax :
|
||||
(int)ui_but_value_get(but);
|
||||
}
|
||||
else if (but->optype) {
|
||||
PointerRNA *opptr = UI_but_operator_ptr_get(but);
|
||||
wmOperatorType *ot = but->optype;
|
||||
else if (optype) {
|
||||
PointerRNA *opptr = extra_icon_optype ? UI_but_extra_operator_icon_opptr_get(extra_icon) :
|
||||
UI_but_operator_ptr_get(but);
|
||||
|
||||
/* so the context is passed to itemf functions */
|
||||
WM_operator_properties_sanitize(opptr, false);
|
||||
|
@ -6998,11 +7027,11 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
|||
* operator menus in the Anim Editors will show tooltips for the different
|
||||
* operations instead of the meaningless generic operator tooltip
|
||||
*/
|
||||
if (ot->prop && RNA_property_type(ot->prop) == PROP_ENUM) {
|
||||
if (RNA_struct_contains_property(opptr, ot->prop)) {
|
||||
if (optype->prop && RNA_property_type(optype->prop) == PROP_ENUM) {
|
||||
if (RNA_struct_contains_property(opptr, optype->prop)) {
|
||||
ptr = opptr;
|
||||
prop = ot->prop;
|
||||
value = RNA_property_enum_get(opptr, ot->prop);
|
||||
prop = optype->prop;
|
||||
value = RNA_property_enum_get(opptr, optype->prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7035,7 +7064,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
|||
else if (type == BUT_GET_OP_KEYMAP) {
|
||||
if (!ui_block_is_menu(but->block)) {
|
||||
char buf[128];
|
||||
if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) {
|
||||
if (ui_but_event_operator_string(C, but, extra_icon, buf, sizeof(buf))) {
|
||||
tmp = BLI_strdup(buf);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -509,7 +509,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
|
|||
uiStringInfo label = {BUT_GET_LABEL, NULL};
|
||||
|
||||
/* highly unlikely getting the label ever fails */
|
||||
UI_but_string_info_get(C, but, &label, NULL);
|
||||
UI_but_string_info_get(C, but, NULL, &label, NULL);
|
||||
|
||||
pup = UI_popup_menu_begin(C, label.strinfo ? label.strinfo : "", ICON_NONE);
|
||||
layout = UI_popup_menu_layout(pup);
|
||||
|
|
|
@ -334,6 +334,7 @@ typedef struct uiHandleButtonData {
|
|||
int retval;
|
||||
/* booleans (could be made into flags) */
|
||||
bool cancel, escapecancel;
|
||||
bool skip_undo_push;
|
||||
bool applied, applied_interactive;
|
||||
bool changed_cursor;
|
||||
wmTimer *flashtimer;
|
||||
|
@ -820,7 +821,9 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
|
|||
/* typically call ui_apply_but_undo(), ui_apply_but_autokey() */
|
||||
static void ui_apply_but_undo(uiBut *but)
|
||||
{
|
||||
if (but->flag & UI_BUT_UNDO) {
|
||||
const bool force_skip_undo = (but->active && but->active->skip_undo_push);
|
||||
|
||||
if (but->flag & UI_BUT_UNDO && !force_skip_undo) {
|
||||
const char *str = NULL;
|
||||
size_t str_len_clip = SIZE_MAX - 1;
|
||||
bool skip_undo = false;
|
||||
|
@ -2866,7 +2869,8 @@ void ui_but_active_string_clear_and_exit(bContext *C, uiBut *but)
|
|||
but->active->str[0] = 0;
|
||||
|
||||
ui_apply_but_TEX(C, but, but->active);
|
||||
button_activate_state(C, but, BUTTON_STATE_EXIT);
|
||||
/* use onfree event so undo is handled by caller and apply is already done above */
|
||||
button_activate_exit((bContext *)C, but, but->active, false, true);
|
||||
}
|
||||
|
||||
static void ui_textedit_string_ensure_max_length(uiBut *but, uiHandleButtonData *data, int maxlen)
|
||||
|
@ -4011,16 +4015,38 @@ static void ui_numedit_apply(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
|
|||
ED_region_tag_redraw(data->region);
|
||||
}
|
||||
|
||||
static void ui_but_extra_operator_icon_apply(bContext *C, uiBut *but, uiButExtraOpIcon *op_icon)
|
||||
static void ui_but_extra_operator_icon_apply_func(uiBut *but, uiButExtraOpIcon *op_icon)
|
||||
{
|
||||
if (but->active->interactive) {
|
||||
ui_apply_but(C, but->block, but, but->active, true);
|
||||
if (ui_afterfunc_check(but->block, but)) {
|
||||
uiAfterFunc *after = ui_afterfunc_new();
|
||||
|
||||
after->optype = op_icon->optype_params->optype;
|
||||
after->opcontext = op_icon->optype_params->opcontext;
|
||||
after->opptr = op_icon->optype_params->opptr;
|
||||
|
||||
if (but->context) {
|
||||
after->context = CTX_store_copy(but->context);
|
||||
}
|
||||
|
||||
/* Ownership moved, don't let the UI code free it. */
|
||||
op_icon->optype_params->opptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_but_extra_operator_icon_apply(bContext *C,
|
||||
uiBut *but,
|
||||
uiHandleButtonData *data,
|
||||
uiButExtraOpIcon *op_icon)
|
||||
{
|
||||
button_activate_state(C, but, BUTTON_STATE_EXIT);
|
||||
WM_operator_name_call_ptr(C,
|
||||
op_icon->optype_params->optype,
|
||||
op_icon->optype_params->opcontext,
|
||||
op_icon->optype_params->opptr);
|
||||
ui_apply_but(C, but->block, but, data, true);
|
||||
|
||||
data->postbut = but;
|
||||
data->posttype = BUTTON_ACTIVATE_OVER;
|
||||
/* Leave undo up to the operator. */
|
||||
data->skip_undo_push = true;
|
||||
|
||||
ui_but_extra_operator_icon_apply_func(but, op_icon);
|
||||
|
||||
/* Force recreation of extra operator icons (pseudo update). */
|
||||
ui_but_extra_operator_icons_free(but);
|
||||
|
@ -4219,7 +4245,7 @@ static bool ui_do_but_extra_operator_icon(bContext *C,
|
|||
ED_region_tag_redraw(data->region);
|
||||
button_tooltip_timer_reset(C, but);
|
||||
|
||||
ui_but_extra_operator_icon_apply(C, but, op_icon);
|
||||
ui_but_extra_operator_icon_apply(C, but, data, op_icon);
|
||||
/* Note: 'but', 'data' may now be freed, don't access. */
|
||||
|
||||
return true;
|
||||
|
@ -7854,7 +7880,10 @@ static ARegion *ui_but_tooltip_init(
|
|||
uiBut *but = UI_region_active_but_get(region);
|
||||
*r_exit_on_event = false;
|
||||
if (but) {
|
||||
return UI_tooltip_create_from_button(C, region, but, is_label);
|
||||
uiButExtraOpIcon *extra_icon = ui_but_extra_operator_icon_mouse_over_get(
|
||||
but, but->active, CTX_wm_window(C)->eventstate);
|
||||
|
||||
return UI_tooltip_create_from_button_or_extra_icon(C, region, but, extra_icon, is_label);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1521,6 +1521,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
|
|||
|
||||
UI_but_string_info_get(C,
|
||||
but,
|
||||
NULL,
|
||||
&but_label,
|
||||
&rna_label,
|
||||
&enum_label,
|
||||
|
|
|
@ -534,7 +534,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
|
|||
|
||||
{
|
||||
uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL};
|
||||
UI_but_string_info_get(C, but, &op_keymap, NULL);
|
||||
UI_but_string_info_get(C, but, NULL, &op_keymap, NULL);
|
||||
shortcut = op_keymap.strinfo;
|
||||
}
|
||||
|
||||
|
@ -764,7 +764,9 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
|
|||
return data;
|
||||
}
|
||||
|
||||
static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
|
||||
static uiTooltipData *ui_tooltip_data_from_button(bContext *C,
|
||||
uiBut *but,
|
||||
uiButExtraOpIcon *extra_icon)
|
||||
{
|
||||
uiStringInfo but_label = {BUT_GET_LABEL, NULL};
|
||||
uiStringInfo but_tip = {BUT_GET_TIP, NULL};
|
||||
|
@ -777,20 +779,29 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
|
|||
|
||||
char buf[512];
|
||||
|
||||
wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon);
|
||||
wmOperatorType *optype = extra_icon ? extra_icon_optype : but->optype;
|
||||
|
||||
/* create tooltip data */
|
||||
uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
|
||||
|
||||
UI_but_string_info_get(C,
|
||||
but,
|
||||
&but_label,
|
||||
&but_tip,
|
||||
&enum_label,
|
||||
&enum_tip,
|
||||
&op_keymap,
|
||||
&prop_keymap,
|
||||
&rna_struct,
|
||||
&rna_prop,
|
||||
NULL);
|
||||
if (extra_icon) {
|
||||
UI_but_string_info_get(C, but, extra_icon, &but_label, &but_tip, &op_keymap, NULL);
|
||||
}
|
||||
else {
|
||||
UI_but_string_info_get(C,
|
||||
but,
|
||||
NULL,
|
||||
&but_label,
|
||||
&but_tip,
|
||||
&enum_label,
|
||||
&enum_tip,
|
||||
&op_keymap,
|
||||
&prop_keymap,
|
||||
&rna_struct,
|
||||
&rna_prop,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Tip Label (only for buttons not already showing the label).
|
||||
* Check prefix instead of comparing because the button may include the shortcut. */
|
||||
|
@ -923,15 +934,16 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (but->optype) {
|
||||
PointerRNA *opptr;
|
||||
char *str;
|
||||
opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */
|
||||
else if (optype) {
|
||||
PointerRNA *opptr = extra_icon_optype ?
|
||||
UI_but_extra_operator_icon_opptr_get(extra_icon) :
|
||||
UI_but_operator_ptr_get(
|
||||
but); /* allocated when needed, the button owns it */
|
||||
|
||||
/* so the context is passed to fieldf functions (some py fieldf functions use it) */
|
||||
WM_operator_properties_sanitize(opptr, false);
|
||||
|
||||
str = ui_tooltip_text_python_from_op(C, but->optype, opptr);
|
||||
char *str = ui_tooltip_text_python_from_op(C, optype, opptr);
|
||||
|
||||
/* operator info */
|
||||
if (U.flag & USER_TOOLTIPS_PYTHON) {
|
||||
|
@ -958,7 +970,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
|
|||
disabled_msg = CTX_wm_operator_poll_msg_get(C);
|
||||
}
|
||||
/* alternatively, buttons can store some reasoning too */
|
||||
else if (but->disabled_info) {
|
||||
if (!disabled_msg && but->disabled_info) {
|
||||
disabled_msg = TIP_(but->disabled_info);
|
||||
}
|
||||
|
||||
|
@ -1398,11 +1410,8 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
|
|||
/** \name ToolTip Public API
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* \param is_label: When true, show a small tip that only shows the name,
|
||||
* otherwise show the full tooltip.
|
||||
*/
|
||||
ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
|
||||
ARegion *UI_tooltip_create_from_button_or_extra_icon(
|
||||
bContext *C, ARegion *butregion, uiBut *but, uiButExtraOpIcon *extra_icon, bool is_label)
|
||||
{
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
/* aspect values that shrink text are likely unreadable */
|
||||
|
@ -1419,7 +1428,7 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b
|
|||
}
|
||||
|
||||
if (data == NULL) {
|
||||
data = ui_tooltip_data_from_button(C, but);
|
||||
data = ui_tooltip_data_from_button(C, but, extra_icon);
|
||||
}
|
||||
|
||||
if (data == NULL) {
|
||||
|
@ -1457,6 +1466,15 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b
|
|||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param is_label: When true, show a small tip that only shows the name,
|
||||
* otherwise show the full tooltip.
|
||||
*/
|
||||
ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label)
|
||||
{
|
||||
return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, NULL, is_label);
|
||||
}
|
||||
|
||||
ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
|
||||
{
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -38,8 +38,11 @@ void OBJECT_OT_material_slot_move(struct wmOperatorType *ot);
|
|||
void OBJECT_OT_material_slot_remove_unused(struct wmOperatorType *ot);
|
||||
|
||||
void MATERIAL_OT_new(struct wmOperatorType *ot);
|
||||
void MATERIAL_OT_duplicate(struct wmOperatorType *ot);
|
||||
void TEXTURE_OT_new(struct wmOperatorType *ot);
|
||||
void TEXTURE_OT_duplicate(struct wmOperatorType *ot);
|
||||
void WORLD_OT_new(struct wmOperatorType *ot);
|
||||
void WORLD_OT_duplicate(struct wmOperatorType *ot);
|
||||
|
||||
void MATERIAL_OT_copy(struct wmOperatorType *ot);
|
||||
void MATERIAL_OT_paste(struct wmOperatorType *ot);
|
||||
|
|
|
@ -45,8 +45,11 @@ void ED_operatortypes_render(void)
|
|||
WM_operatortype_append(OBJECT_OT_material_slot_remove_unused);
|
||||
|
||||
WM_operatortype_append(MATERIAL_OT_new);
|
||||
WM_operatortype_append(MATERIAL_OT_duplicate);
|
||||
WM_operatortype_append(TEXTURE_OT_new);
|
||||
WM_operatortype_append(TEXTURE_OT_duplicate);
|
||||
WM_operatortype_append(WORLD_OT_new);
|
||||
WM_operatortype_append(WORLD_OT_duplicate);
|
||||
|
||||
WM_operatortype_append(MATERIAL_OT_copy);
|
||||
WM_operatortype_append(MATERIAL_OT_paste);
|
||||
|
|
|
@ -735,45 +735,40 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot)
|
|||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name New Material Operator
|
||||
/** \name Create Material Operators
|
||||
* \{ */
|
||||
|
||||
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
struct MaterialCreationData {
|
||||
Object *ob;
|
||||
PropertyPointerRNA pprop;
|
||||
};
|
||||
|
||||
static void material_creation_data_init_from_UI_context(bContext *C,
|
||||
struct MaterialCreationData *r_create_data)
|
||||
{
|
||||
Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
|
||||
Main *bmain = CTX_data_main(C);
|
||||
PointerRNA ptr, idptr;
|
||||
PointerRNA ptr;
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* hook into UI */
|
||||
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
|
||||
|
||||
Object *ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL;
|
||||
r_create_data->ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL;
|
||||
r_create_data->pprop.ptr = ptr;
|
||||
r_create_data->pprop.prop = prop;
|
||||
}
|
||||
|
||||
/* add or copy material */
|
||||
if (ma) {
|
||||
Material *new_ma = (Material *)BKE_id_copy_ex(
|
||||
bmain, &ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
|
||||
ma = new_ma;
|
||||
}
|
||||
else {
|
||||
const char *name = DATA_("Material");
|
||||
if (!(ob != NULL && ob->type == OB_GPENCIL)) {
|
||||
ma = BKE_material_add(bmain, name);
|
||||
}
|
||||
else {
|
||||
ma = BKE_gpencil_material_add(bmain, name);
|
||||
}
|
||||
ED_node_shader_default(C, &ma->id);
|
||||
ma->use_nodes = true;
|
||||
}
|
||||
static void material_creation_assign(bContext *C,
|
||||
Material *ma,
|
||||
struct MaterialCreationData *create_data)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
if (prop) {
|
||||
if (ob != NULL) {
|
||||
if (create_data->pprop.prop) {
|
||||
if (create_data->ob != NULL) {
|
||||
/* Add slot follows user-preferences for creating new slots,
|
||||
* RNA pointer assignment doesn't, see: T60014. */
|
||||
if (BKE_object_material_get_p(ob, ob->actcol) == NULL) {
|
||||
BKE_object_material_slot_add(bmain, ob);
|
||||
if (BKE_object_material_get_p(create_data->ob, create_data->ob->actcol) == NULL) {
|
||||
BKE_object_material_slot_add(bmain, create_data->ob);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -781,10 +776,32 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
|
|||
* pointer use also increases user, so this compensates it */
|
||||
id_us_min(&ma->id);
|
||||
|
||||
PointerRNA idptr;
|
||||
RNA_id_pointer_create(&ma->id, &idptr);
|
||||
RNA_property_pointer_set(&ptr, prop, idptr, NULL);
|
||||
RNA_property_update(C, &ptr, prop);
|
||||
RNA_property_pointer_set(&create_data->pprop.ptr, create_data->pprop.prop, idptr, NULL);
|
||||
RNA_property_update(C, &create_data->pprop.ptr, create_data->pprop.prop);
|
||||
}
|
||||
}
|
||||
|
||||
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
struct MaterialCreationData create_data;
|
||||
|
||||
material_creation_data_init_from_UI_context(C, &create_data);
|
||||
|
||||
const char *name = DATA_("Material");
|
||||
Material *ma;
|
||||
if ((create_data.ob == NULL) || (create_data.ob->type != OB_GPENCIL)) {
|
||||
ma = BKE_material_add(bmain, name);
|
||||
}
|
||||
else {
|
||||
ma = BKE_gpencil_material_add(bmain, name);
|
||||
}
|
||||
ED_node_shader_default(C, &ma->id);
|
||||
ma->use_nodes = true;
|
||||
|
||||
material_creation_assign(C, ma, &create_data);
|
||||
|
||||
WM_event_add_notifier(C, NC_MATERIAL | NA_ADDED, ma);
|
||||
|
||||
|
@ -806,27 +823,57 @@ void MATERIAL_OT_new(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
static int duplicate_material_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Material *old_ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
|
||||
|
||||
if (!old_ma) {
|
||||
BKE_report(
|
||||
op->reports,
|
||||
RPT_ERROR,
|
||||
"Incorrect context for duplicating a material (did not find material to duplicate)");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Main *bmain = CTX_data_main(C);
|
||||
struct MaterialCreationData create_data;
|
||||
|
||||
material_creation_data_init_from_UI_context(C, &create_data);
|
||||
|
||||
Material *new_ma = (Material *)BKE_id_copy_ex(
|
||||
bmain, &old_ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
|
||||
|
||||
material_creation_assign(C, new_ma, &create_data);
|
||||
|
||||
WM_event_add_notifier(C, NC_MATERIAL | NA_ADDED, new_ma);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void MATERIAL_OT_duplicate(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Duplicate Material";
|
||||
ot->idname = "MATERIAL_OT_duplicate";
|
||||
ot->description = "Duplicate an existing material";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = duplicate_material_exec;
|
||||
ot->poll = object_materials_supported_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name New Texture Operator
|
||||
/** \name Create Texture Operators
|
||||
* \{ */
|
||||
|
||||
static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
static void texture_creation_assign(bContext *C, Tex *tex)
|
||||
{
|
||||
Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
|
||||
Main *bmain = CTX_data_main(C);
|
||||
PointerRNA ptr, idptr;
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* add or copy texture */
|
||||
if (tex) {
|
||||
tex = (Tex *)BKE_id_copy(bmain, &tex->id);
|
||||
}
|
||||
else {
|
||||
tex = BKE_texture_add(bmain, DATA_("Texture"));
|
||||
}
|
||||
|
||||
/* hook into UI */
|
||||
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
|
||||
|
||||
|
@ -839,6 +886,14 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
|
|||
RNA_property_pointer_set(&ptr, prop, idptr, NULL);
|
||||
RNA_property_update(C, &ptr, prop);
|
||||
}
|
||||
}
|
||||
|
||||
static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Tex *tex = BKE_texture_add(bmain, DATA_("Texture"));
|
||||
|
||||
texture_creation_assign(C, tex);
|
||||
|
||||
WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, tex);
|
||||
|
||||
|
@ -859,31 +914,53 @@ void TEXTURE_OT_new(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
static int duplicate_texture_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
|
||||
|
||||
if (!tex) {
|
||||
BKE_report(op->reports,
|
||||
RPT_ERROR,
|
||||
"Incorrect context for duplicating a texture (did not find texture to duplicate)");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* add or copy texture */
|
||||
Main *bmain = CTX_data_main(C);
|
||||
tex = (Tex *)BKE_id_copy(bmain, &tex->id);
|
||||
|
||||
texture_creation_assign(C, tex);
|
||||
|
||||
WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, tex);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void TEXTURE_OT_duplicate(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Duplicate Texture";
|
||||
ot->idname = "TEXTURE_OT_duplicate";
|
||||
ot->description = "Duplicate an existing texture";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = duplicate_texture_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name new world operator
|
||||
/** \name Create world operators
|
||||
* \{ */
|
||||
|
||||
static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
static void world_creation_assign(bContext *C, World *wo)
|
||||
{
|
||||
World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
|
||||
Main *bmain = CTX_data_main(C);
|
||||
PointerRNA ptr, idptr;
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* add or copy world */
|
||||
if (wo) {
|
||||
World *new_wo = (World *)BKE_id_copy_ex(
|
||||
bmain, &wo->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
|
||||
wo = new_wo;
|
||||
}
|
||||
else {
|
||||
wo = BKE_world_add(bmain, DATA_("World"));
|
||||
ED_node_shader_default(C, &wo->id);
|
||||
wo->use_nodes = true;
|
||||
}
|
||||
|
||||
/* hook into UI */
|
||||
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
|
||||
|
||||
|
@ -896,6 +973,17 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
|
|||
RNA_property_pointer_set(&ptr, prop, idptr, NULL);
|
||||
RNA_property_update(C, &ptr, prop);
|
||||
}
|
||||
}
|
||||
|
||||
static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
World *wo = BKE_world_add(bmain, DATA_("World"));
|
||||
ED_node_shader_default(C, &wo->id);
|
||||
wo->use_nodes = true;
|
||||
|
||||
world_creation_assign(C, wo);
|
||||
|
||||
WM_event_add_notifier(C, NC_WORLD | NA_ADDED, wo);
|
||||
|
||||
|
@ -907,7 +995,7 @@ void WORLD_OT_new(wmOperatorType *ot)
|
|||
/* identifiers */
|
||||
ot->name = "New World";
|
||||
ot->idname = "WORLD_OT_new";
|
||||
ot->description = "Create a new world Data-Block";
|
||||
ot->description = "Create a new world data-block";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = new_world_exec;
|
||||
|
@ -916,6 +1004,36 @@ void WORLD_OT_new(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
static int duplicate_world_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
|
||||
|
||||
if (wo) {
|
||||
Main *bmain = CTX_data_main(C);
|
||||
wo = (World *)BKE_id_copy(bmain, &wo->id);
|
||||
}
|
||||
|
||||
world_creation_assign(C, wo);
|
||||
|
||||
WM_event_add_notifier(C, NC_WORLD | NA_ADDED, wo);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void WORLD_OT_duplicate(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Duplicate World";
|
||||
ot->idname = "WORLD_OT_duplicate";
|
||||
ot->description = "Duplicate an existing world data-block";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = duplicate_world_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -5509,7 +5509,6 @@ void ED_operatortypes_screen(void)
|
|||
WM_operatortype_append(ED_OT_undo_redo);
|
||||
WM_operatortype_append(ED_OT_undo_history);
|
||||
|
||||
WM_operatortype_append(ED_OT_flush_edits);
|
||||
WM_operatortype_append(ED_OT_lib_id_load_custom_preview);
|
||||
WM_operatortype_append(ED_OT_lib_id_generate_preview);
|
||||
}
|
||||
|
|
|
@ -158,7 +158,78 @@ static void actedit_change_action(bContext *C, bAction *act)
|
|||
RNA_property_update(C, &ptr, prop);
|
||||
}
|
||||
|
||||
/* ******************** New Action Operator *********************** */
|
||||
/* ******************** New Action Operators *********************** */
|
||||
|
||||
static void action_creation_assign(bContext *C,
|
||||
bAction *action,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop)
|
||||
{
|
||||
PointerRNA idptr;
|
||||
/* Set the new action.
|
||||
* NOTE: we can't use actedit_change_action, as this function is also called from the NLA. */
|
||||
RNA_id_pointer_create(&action->id, &idptr);
|
||||
RNA_property_pointer_set(ptr, prop, idptr, NULL);
|
||||
RNA_property_update(C, ptr, prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stash the previously active action to prevent it from being lost.
|
||||
* \return The old action if any.
|
||||
*/
|
||||
static bAction *action_creation_stash_old(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
|
||||
{
|
||||
bAction *oldact = NULL;
|
||||
AnimData *adt = NULL;
|
||||
|
||||
if (prop) {
|
||||
/* The operator was called from a button. */
|
||||
PointerRNA oldptr;
|
||||
|
||||
oldptr = RNA_property_pointer_get(ptr, prop);
|
||||
oldact = (bAction *)oldptr.owner_id;
|
||||
|
||||
/* stash the old action to prevent it from being lost */
|
||||
if (ptr->type == &RNA_AnimData) {
|
||||
adt = ptr->data;
|
||||
}
|
||||
else if (ptr->type == &RNA_SpaceDopeSheetEditor) {
|
||||
adt = ED_actedit_animdata_from_context(C);
|
||||
}
|
||||
}
|
||||
else {
|
||||
adt = ED_actedit_animdata_from_context(C);
|
||||
oldact = adt->action;
|
||||
}
|
||||
|
||||
if (!adt || !oldact) {
|
||||
/* Found nothing to stash in current context. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Perform stashing operation. */
|
||||
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ptr->owner_id))) {
|
||||
/* The stash operation will remove the user already
|
||||
* (and unlink the action from the AnimData action slot).
|
||||
* Hence, we must unset the ref to the action in the
|
||||
* action editor too (if this is where we're being called from)
|
||||
* first before setting the new action once it is created,
|
||||
* or else the user gets decremented twice!
|
||||
*/
|
||||
if (ptr->type == &RNA_SpaceDopeSheetEditor) {
|
||||
SpaceAction *saction = ptr->data;
|
||||
saction->action = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if 0
|
||||
printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n",
|
||||
oldact->id.name);
|
||||
#endif
|
||||
}
|
||||
|
||||
return oldact;
|
||||
}
|
||||
|
||||
/* Criteria:
|
||||
* 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions...
|
||||
|
@ -207,71 +278,17 @@ static bool action_new_poll(bContext *C)
|
|||
|
||||
static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
PointerRNA ptr, idptr;
|
||||
PointerRNA ptr;
|
||||
PropertyRNA *prop;
|
||||
|
||||
bAction *oldact = NULL;
|
||||
AnimData *adt = NULL;
|
||||
/* hook into UI */
|
||||
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
|
||||
|
||||
action_creation_stash_old(C, &ptr, prop);
|
||||
|
||||
bAction *action = action_create_new(C, NULL);
|
||||
if (prop) {
|
||||
/* The operator was called from a button. */
|
||||
PointerRNA oldptr;
|
||||
|
||||
oldptr = RNA_property_pointer_get(&ptr, prop);
|
||||
oldact = (bAction *)oldptr.owner_id;
|
||||
|
||||
/* stash the old action to prevent it from being lost */
|
||||
if (ptr.type == &RNA_AnimData) {
|
||||
adt = ptr.data;
|
||||
}
|
||||
else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
|
||||
adt = ED_actedit_animdata_from_context(C);
|
||||
}
|
||||
}
|
||||
else {
|
||||
adt = ED_actedit_animdata_from_context(C);
|
||||
oldact = adt->action;
|
||||
}
|
||||
{
|
||||
bAction *action = NULL;
|
||||
|
||||
/* Perform stashing operation - But only if there is an action */
|
||||
if (adt && oldact) {
|
||||
/* stash the action */
|
||||
if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ptr.owner_id))) {
|
||||
/* The stash operation will remove the user already
|
||||
* (and unlink the action from the AnimData action slot).
|
||||
* Hence, we must unset the ref to the action in the
|
||||
* action editor too (if this is where we're being called from)
|
||||
* first before setting the new action once it is created,
|
||||
* or else the user gets decremented twice!
|
||||
*/
|
||||
if (ptr.type == &RNA_SpaceDopeSheetEditor) {
|
||||
SpaceAction *saction = ptr.data;
|
||||
saction->action = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if 0
|
||||
printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n",
|
||||
oldact->id.name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* create action */
|
||||
action = action_create_new(C, oldact);
|
||||
|
||||
if (prop) {
|
||||
/* set this new action
|
||||
* NOTE: we can't use actedit_change_action, as this function is also called from the NLA
|
||||
*/
|
||||
RNA_id_pointer_create(&action->id, &idptr);
|
||||
RNA_property_pointer_set(&ptr, prop, idptr, NULL);
|
||||
RNA_property_update(C, &ptr, prop);
|
||||
}
|
||||
action_creation_assign(C, action, &ptr, prop);
|
||||
}
|
||||
|
||||
/* set notifier that keyframes have changed */
|
||||
|
@ -285,7 +302,7 @@ void ACTION_OT_new(wmOperatorType *ot)
|
|||
/* identifiers */
|
||||
ot->name = "New Action";
|
||||
ot->idname = "ACTION_OT_new";
|
||||
ot->description = "Create new action";
|
||||
ot->description = "Create a new action";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = action_new_exec;
|
||||
|
@ -295,6 +312,45 @@ void ACTION_OT_new(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static int action_duplicate_assign_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
PointerRNA ptr;
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* hook into UI */
|
||||
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
|
||||
|
||||
bAction *old_action = action_creation_stash_old(C, &ptr, prop);
|
||||
|
||||
bAction *new_action = action_create_new(C, old_action);
|
||||
if (prop) {
|
||||
action_creation_assign(C, new_action, &ptr, prop);
|
||||
}
|
||||
|
||||
/* set notifier that keyframes have changed */
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate an action assigned to a templateID and update it's assignment - based on UI context.
|
||||
*/
|
||||
void ACTION_OT_duplicate_assign(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Duplicate & Assign Action";
|
||||
ot->idname = "ACTION_OT_duplicate_assign";
|
||||
ot->description = "Create a copy of an existing action and assign it";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = action_duplicate_assign_exec;
|
||||
ot->poll = action_new_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/* ******************* Action Push-Down Operator ******************** */
|
||||
|
||||
/* Criteria:
|
||||
|
|
|
@ -106,6 +106,7 @@ void ACTION_OT_snap(struct wmOperatorType *ot);
|
|||
void ACTION_OT_mirror(struct wmOperatorType *ot);
|
||||
|
||||
void ACTION_OT_new(struct wmOperatorType *ot);
|
||||
void ACTION_OT_duplicate_assign(struct wmOperatorType *ot);
|
||||
void ACTION_OT_unlink(struct wmOperatorType *ot);
|
||||
|
||||
void ACTION_OT_push_down(struct wmOperatorType *ot);
|
||||
|
|
|
@ -73,7 +73,9 @@ void action_operatortypes(void)
|
|||
WM_operatortype_append(ACTION_OT_copy);
|
||||
WM_operatortype_append(ACTION_OT_paste);
|
||||
|
||||
/* UI-context based operators. */
|
||||
WM_operatortype_append(ACTION_OT_new);
|
||||
WM_operatortype_append(ACTION_OT_duplicate_assign);
|
||||
WM_operatortype_append(ACTION_OT_unlink);
|
||||
|
||||
WM_operatortype_append(ACTION_OT_push_down);
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "ED_space_api.h"
|
||||
#include "ED_transform.h"
|
||||
#include "ED_userpref.h"
|
||||
#include "ED_util.h"
|
||||
#include "ED_uvedit.h"
|
||||
|
||||
#include "io_ops.h"
|
||||
|
@ -124,6 +125,7 @@ void ED_spacetypes_init(void)
|
|||
ED_operatortypes_render();
|
||||
ED_operatortypes_mask();
|
||||
ED_operatortypes_io();
|
||||
ED_operatortypes_edutils();
|
||||
|
||||
ED_operatortypes_view2d();
|
||||
ED_operatortypes_ui();
|
||||
|
|
|
@ -140,6 +140,7 @@ void uiTemplateMovieClip(
|
|||
ptr,
|
||||
propname,
|
||||
NULL,
|
||||
NULL,
|
||||
"CLIP_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
|
|
|
@ -180,11 +180,16 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *panel)
|
|||
UI_but_funcN_set(but, file_filename_enter_handle, NULL, but);
|
||||
|
||||
if (params->flag & FILE_CHECK_EXISTING) {
|
||||
but_extra_rna_ptr = UI_but_extra_operator_icon_add(
|
||||
uiButExtraOpIcon *extra_icon;
|
||||
|
||||
extra_icon = UI_but_extra_operator_icon_add(
|
||||
but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_REMOVE);
|
||||
but_extra_rna_ptr = UI_but_extra_operator_icon_opptr_get(extra_icon);
|
||||
RNA_int_set(but_extra_rna_ptr, "increment", -1);
|
||||
but_extra_rna_ptr = UI_but_extra_operator_icon_add(
|
||||
|
||||
extra_icon = UI_but_extra_operator_icon_add(
|
||||
but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_ADD);
|
||||
but_extra_rna_ptr = UI_but_extra_operator_icon_opptr_get(extra_icon);
|
||||
RNA_int_set(but_extra_rna_ptr, "increment", 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -806,7 +806,8 @@ void uiTemplateImage(uiLayout *layout,
|
|||
C,
|
||||
ptr,
|
||||
propname,
|
||||
ima ? NULL : "IMAGE_OT_new",
|
||||
"IMAGE_OT_new",
|
||||
NULL,
|
||||
"IMAGE_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
|
|
|
@ -292,8 +292,9 @@ static void nla_panel_animdata(const bContext *C, Panel *panel)
|
|||
(bContext *)C,
|
||||
&adt_ptr,
|
||||
"action",
|
||||
"ACTION_OT_new",
|
||||
NULL,
|
||||
"ACTION_OT_new",
|
||||
"ACTION_OT_duplicate_assign",
|
||||
"NLA_OT_action_unlink",
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
false,
|
||||
|
|
|
@ -771,6 +771,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
|
|||
ptr,
|
||||
"image",
|
||||
"IMAGE_OT_new",
|
||||
NULL,
|
||||
"IMAGE_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
|
@ -808,6 +809,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
|
|||
ptr,
|
||||
"image",
|
||||
"IMAGE_OT_new",
|
||||
NULL,
|
||||
"IMAGE_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
|
@ -1395,6 +1397,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
|
|||
ptr,
|
||||
"image",
|
||||
"IMAGE_OT_new",
|
||||
NULL,
|
||||
"IMAGE_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
|
@ -1426,7 +1429,8 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer
|
|||
bNode *node = ptr->data;
|
||||
uiLayout *col, *row;
|
||||
|
||||
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "scene", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
|
||||
if (!node->id) {
|
||||
return;
|
||||
|
@ -1548,7 +1552,8 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA
|
|||
col = uiLayoutColumn(layout, false);
|
||||
uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, NULL, ICON_NONE);
|
||||
|
||||
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "scene", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
|
||||
col = uiLayoutColumn(layout, false);
|
||||
uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, NULL, ICON_NONE);
|
||||
|
@ -2163,8 +2168,17 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe
|
|||
|
||||
static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiTemplateID(layout,
|
||||
C,
|
||||
ptr,
|
||||
"clip",
|
||||
NULL,
|
||||
NULL,
|
||||
"CLIP_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
false,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
|
@ -2172,8 +2186,17 @@ static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, Point
|
|||
bNode *node = ptr->data;
|
||||
PointerRNA clipptr;
|
||||
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiTemplateID(layout,
|
||||
C,
|
||||
ptr,
|
||||
"clip",
|
||||
NULL,
|
||||
NULL,
|
||||
"CLIP_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
false,
|
||||
NULL);
|
||||
|
||||
if (!node->id) {
|
||||
return;
|
||||
|
@ -2188,8 +2211,17 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe
|
|||
{
|
||||
bNode *node = ptr->data;
|
||||
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiTemplateID(layout,
|
||||
C,
|
||||
ptr,
|
||||
"clip",
|
||||
NULL,
|
||||
NULL,
|
||||
"CLIP_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
false,
|
||||
NULL);
|
||||
|
||||
if (!node->id) {
|
||||
return;
|
||||
|
@ -2214,8 +2246,17 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po
|
|||
{
|
||||
bNode *node = ptr->data;
|
||||
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiTemplateID(layout,
|
||||
C,
|
||||
ptr,
|
||||
"clip",
|
||||
NULL,
|
||||
NULL,
|
||||
"CLIP_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
false,
|
||||
NULL);
|
||||
|
||||
if (!node->id) {
|
||||
return;
|
||||
|
@ -2538,7 +2579,8 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p
|
|||
{
|
||||
bNode *node = ptr->data;
|
||||
|
||||
uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "mask", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, NULL, ICON_NONE);
|
||||
|
||||
uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE);
|
||||
|
@ -2559,7 +2601,8 @@ static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, Point
|
|||
{
|
||||
bNode *node = ptr->data;
|
||||
|
||||
uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "clip", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
|
||||
if (node->id) {
|
||||
MovieClip *clip = (MovieClip *)node->id;
|
||||
|
@ -2595,8 +2638,17 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
|
|||
{
|
||||
bNode *node = ptr->data;
|
||||
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiTemplateID(layout,
|
||||
C,
|
||||
ptr,
|
||||
"clip",
|
||||
NULL,
|
||||
NULL,
|
||||
"CLIP_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
false,
|
||||
NULL);
|
||||
|
||||
if (node->id) {
|
||||
MovieClip *clip = (MovieClip *)node->id;
|
||||
|
@ -2636,8 +2688,17 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
|
|||
bNode *node = ptr->data;
|
||||
NodePlaneTrackDeformData *data = node->storage;
|
||||
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
|
||||
uiTemplateID(layout,
|
||||
C,
|
||||
ptr,
|
||||
"clip",
|
||||
NULL,
|
||||
NULL,
|
||||
"CLIP_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
false,
|
||||
NULL);
|
||||
|
||||
if (node->id) {
|
||||
MovieClip *clip = (MovieClip *)node->id;
|
||||
|
@ -3072,6 +3133,7 @@ static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *p
|
|||
ptr,
|
||||
"image",
|
||||
"IMAGE_OT_new",
|
||||
NULL,
|
||||
"IMAGE_OT_open",
|
||||
NULL,
|
||||
UI_TEMPLATE_ID_FILTER_ALL,
|
||||
|
|
|
@ -39,6 +39,7 @@ set(SRC
|
|||
ed_transverts.c
|
||||
ed_util.c
|
||||
ed_util_imbuf.c
|
||||
ed_util_ops.c
|
||||
gizmo_utils.c
|
||||
numinput.c
|
||||
select_utils.c
|
||||
|
|
|
@ -485,27 +485,6 @@ void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_i
|
|||
}
|
||||
}
|
||||
|
||||
static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
ED_editors_flush_edits(bmain);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void ED_OT_flush_edits(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Flush Edits";
|
||||
ot->description = "Flush edit data from active editing modes";
|
||||
ot->idname = "ED_OT_flush_edits";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = ed_flush_edits_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
static bool lib_id_preview_editing_poll(bContext *C)
|
||||
{
|
||||
const PointerRNA idptr = CTX_data_pointer_get(C, "id");
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup edutil
|
||||
*
|
||||
* Utility operators for UI data or for the UI to use.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
#include "ED_util.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
static int lib_fake_user_toggle_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
PropertyPointerRNA pprop;
|
||||
PointerRNA idptr = PointerRNA_NULL;
|
||||
|
||||
UI_context_active_but_prop_get_templateID(C, &pprop.ptr, &pprop.prop);
|
||||
|
||||
if (pprop.prop) {
|
||||
idptr = RNA_property_pointer_get(&pprop.ptr, pprop.prop);
|
||||
}
|
||||
|
||||
if ((pprop.prop == NULL) || RNA_pointer_is_null(&idptr) || !RNA_struct_is_ID(idptr.type)) {
|
||||
BKE_report(
|
||||
op->reports, RPT_ERROR, "Incorrect context for running data-block fake user toggling");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ID *id = idptr.data;
|
||||
|
||||
if ((id->lib != NULL) || (ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Data-block type does not support fake user");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (ID_FAKE_USERS(id)) {
|
||||
id_fake_user_clear(id);
|
||||
}
|
||||
else {
|
||||
id_fake_user_set(id);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ED_OT_lib_fake_user_toggle(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Toggle Fake User";
|
||||
ot->description = "Save this data-block even if it has no users";
|
||||
ot->idname = "ED_OT_lib_fake_user_toggle";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = lib_fake_user_toggle_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
static int lib_unlink_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
PropertyPointerRNA pprop;
|
||||
PointerRNA idptr;
|
||||
|
||||
UI_context_active_but_prop_get_templateID(C, &pprop.ptr, &pprop.prop);
|
||||
|
||||
if (pprop.prop) {
|
||||
idptr = RNA_property_pointer_get(&pprop.ptr, pprop.prop);
|
||||
}
|
||||
|
||||
if ((pprop.prop == NULL) || RNA_pointer_is_null(&idptr) || !RNA_struct_is_ID(idptr.type)) {
|
||||
BKE_report(
|
||||
op->reports, RPT_ERROR, "Incorrect context for running data-block fake user toggling");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
memset(&idptr, 0, sizeof(idptr));
|
||||
RNA_property_pointer_set(&pprop.ptr, pprop.prop, idptr, NULL);
|
||||
RNA_property_update(C, &pprop.ptr, pprop.prop);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ED_OT_lib_unlink(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Unlink Data-Block";
|
||||
ot->description = "Remove a usage of a data-block, clearing the assignment";
|
||||
ot->idname = "ED_OT_lib_unlink";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = lib_unlink_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
ED_editors_flush_edits(bmain);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ED_OT_flush_edits(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Flush Edits";
|
||||
ot->description = "Flush edit data from active editing modes";
|
||||
ot->idname = "ED_OT_flush_edits";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = ed_flush_edits_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
void ED_operatortypes_edutils(void)
|
||||
{
|
||||
WM_operatortype_append(ED_OT_lib_fake_user_toggle);
|
||||
WM_operatortype_append(ED_OT_lib_unlink);
|
||||
WM_operatortype_append(ED_OT_flush_edits);
|
||||
}
|
|
@ -480,6 +480,7 @@ static void rna_uiTemplateID(uiLayout *layout,
|
|||
PointerRNA *ptr,
|
||||
const char *propname,
|
||||
const char *newop,
|
||||
const char *duplicateop,
|
||||
const char *openop,
|
||||
const char *unlinkop,
|
||||
int filter,
|
||||
|
@ -498,7 +499,8 @@ static void rna_uiTemplateID(uiLayout *layout,
|
|||
/* Get translated name (label). */
|
||||
name = rna_translate_ui_text(name, text_ctxt, NULL, prop, translate);
|
||||
|
||||
uiTemplateID(layout, C, ptr, propname, newop, openop, unlinkop, filter, live_icon, name);
|
||||
uiTemplateID(
|
||||
layout, C, ptr, propname, newop, duplicateop, openop, unlinkop, filter, live_icon, name);
|
||||
}
|
||||
|
||||
static void rna_uiTemplateAnyID(uiLayout *layout,
|
||||
|
@ -1155,9 +1157,12 @@ void RNA_api_ui_layout(StructRNA *srna)
|
|||
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||
api_ui_item_rna_common(func);
|
||||
RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new ID block");
|
||||
RNA_def_string(
|
||||
func, "duplicate", NULL, 0, "", "Operator identifier to duplicate the selected ID block");
|
||||
RNA_def_string(
|
||||
func, "open", NULL, 0, "", "Operator identifier to open a file for creating a new ID block");
|
||||
RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block");
|
||||
RNA_def_string(
|
||||
func, "unlink", NULL, 0, "", "Operator identifier to unlink the selected ID block");
|
||||
RNA_def_enum(func,
|
||||
"filter",
|
||||
id_template_filter_items,
|
||||
|
|
|
@ -437,7 +437,7 @@ static void panel_draw(const bContext *C, Panel *panel)
|
|||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL);
|
||||
uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, NULL, 0, ICON_NONE, NULL);
|
||||
|
||||
col = uiLayoutColumn(layout, false);
|
||||
uiLayoutSetActive(col, has_texture);
|
||||
|
|
|
@ -1031,6 +1031,7 @@ static void panel_draw(const bContext *C, Panel *panel)
|
|||
"node.new_geometry_node_group_assign",
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0,
|
||||
false,
|
||||
nullptr);
|
||||
|
|
|
@ -113,7 +113,8 @@ static void panel_draw(const bContext *C, Panel *panel)
|
|||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
uiTemplateID(layout, C, ptr, "texture", "texture.new", nullptr, nullptr, 0, ICON_NONE, nullptr);
|
||||
uiTemplateID(
|
||||
layout, C, ptr, "texture", "texture.new", nullptr, nullptr, nullptr, 0, ICON_NONE, nullptr);
|
||||
uiItemR(layout, ptr, "texture_map_mode", 0, "Texture Mapping", ICON_NONE);
|
||||
|
||||
if (vdmd->texture_map_mode == MOD_VOLUME_DISPLACE_MAP_OBJECT) {
|
||||
|
|
|
@ -466,7 +466,17 @@ static void texture_panel_draw(const bContext *C, Panel *panel)
|
|||
|
||||
int texture_coords = RNA_enum_get(ptr, "texture_coords");
|
||||
|
||||
uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL);
|
||||
uiTemplateID(layout,
|
||||
C,
|
||||
ptr,
|
||||
"texture",
|
||||
"texture.new",
|
||||
"texture.duplicate",
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
ICON_NONE,
|
||||
NULL);
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
|
|
|
@ -436,7 +436,17 @@ static void texture_panel_draw(const bContext *C, Panel *panel)
|
|||
|
||||
int texture_coords = RNA_enum_get(ptr, "texture_coords");
|
||||
|
||||
uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL);
|
||||
uiTemplateID(layout,
|
||||
C,
|
||||
ptr,
|
||||
"texture",
|
||||
"texture.new",
|
||||
"texture.duplicate",
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
ICON_NONE,
|
||||
NULL);
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
|
|
|
@ -363,6 +363,7 @@ void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr,
|
|||
ptr,
|
||||
"mask_texture",
|
||||
"texture.new",
|
||||
"texture.duplicate",
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
|
|
|
@ -596,7 +596,7 @@ char *WM_operatortype_description(struct bContext *C,
|
|||
struct wmOperatorType *ot,
|
||||
struct PointerRNA *properties)
|
||||
{
|
||||
if (ot->get_description && properties) {
|
||||
if (C && ot->get_description && properties) {
|
||||
char *description = ot->get_description(C, ot, properties);
|
||||
|
||||
if (description) {
|
||||
|
|
Loading…
Reference in New Issue