diff options
Diffstat (limited to 'source/blender/editors/interface/interface_ops.c')
-rw-r--r-- | source/blender/editors/interface/interface_ops.c | 266 |
1 files changed, 228 insertions, 38 deletions
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 7b59a6f7263..f7424066ad8 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -26,7 +26,8 @@ #include "MEM_guardedalloc.h" #include "DNA_armature_types.h" -#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */ +#include "DNA_modifier_types.h" /* for handling geometry nodes properties */ +#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */ #include "DNA_screen_types.h" #include "DNA_text_types.h" @@ -846,9 +847,15 @@ bool UI_context_copy_to_selected_list(bContext *C, else if (RNA_struct_is_a(ptr->type, &RNA_Keyframe)) { *r_lb = CTX_data_collection_get(C, "selected_editable_keyframes"); } + else if (RNA_struct_is_a(ptr->type, &RNA_Action)) { + *r_lb = CTX_data_collection_get(C, "selected_editable_actions"); + } else if (RNA_struct_is_a(ptr->type, &RNA_NlaStrip)) { *r_lb = CTX_data_collection_get(C, "selected_nla_strips"); } + else if (RNA_struct_is_a(ptr->type, &RNA_MovieTrackingTrack)) { + *r_lb = CTX_data_collection_get(C, "selected_movieclip_tracks"); + } else if (RNA_struct_is_a(ptr->type, &RNA_Constraint) && (path_from_bone = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_PoseBone)) != NULL) { @@ -979,6 +986,97 @@ bool UI_context_copy_to_selected_list(bContext *C, return true; } +bool UI_context_copy_to_selected_check(PointerRNA *ptr, + PointerRNA *ptr_link, + PropertyRNA *prop, + const char *path, + bool use_path_from_id, + PointerRNA *r_ptr, + PropertyRNA **r_prop) +{ + PointerRNA idptr; + PropertyRNA *lprop; + PointerRNA lptr; + + if (ptr_link->data == ptr->data) { + return false; + } + + if (use_path_from_id) { + /* Path relative to ID. */ + lprop = NULL; + RNA_id_pointer_create(ptr_link->owner_id, &idptr); + RNA_path_resolve_property(&idptr, path, &lptr, &lprop); + } + else if (path) { + /* Path relative to elements from list. */ + lprop = NULL; + RNA_path_resolve_property(ptr_link, path, &lptr, &lprop); + } + else { + lptr = *ptr_link; + lprop = prop; + } + + if (lptr.data == ptr->data) { + /* temp_ptr might not be the same as ptr_link! */ + return false; + } + + /* Skip non-existing properties on link. This was previously covered with the `lprop != prop` + * check but we are now more permissive when it comes to ID properties, see below. */ + if (lprop == NULL) { + return false; + } + + if (RNA_property_type(lprop) != RNA_property_type(prop)) { + return false; + } + + /* Check property pointers matching. + * For ID properties, these pointers match: + * - If the property is API defined on an existing class (and they are equally named). + * - Never for ID properties on specific ID (even if they are equally named). + * - Never for NodesModifierSettings properties (even if they are equally named). + * + * Be permissive on ID properties in the following cases: + * - #NodesModifierSettings properties + * - (special check: only if the node-group matches, since the 'Input_n' properties are name + * based and similar on potentially very different node-groups). + * - ID properties on specific ID + * - (no special check, copying seems OK [even if type does not match -- does not do anything + * then]) + */ + bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop); + if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) && + RNA_struct_is_a(ptr->type, &RNA_NodesModifier)) { + ignore_prop_eq = false; + + NodesModifierData *nmd_link = (NodesModifierData *)lptr.data; + NodesModifierData *nmd_src = (NodesModifierData *)ptr->data; + if (nmd_link->node_group == nmd_src->node_group) { + ignore_prop_eq = true; + } + } + + if ((lprop != prop) && !ignore_prop_eq) { + return false; + } + + if (!RNA_property_editable(&lptr, lprop)) { + return false; + } + + if (r_ptr) { + *r_ptr = lptr; + } + if (r_prop) { + *r_prop = lprop; + } + + return true; +} + /** * Called from both exec & poll. * @@ -989,7 +1087,7 @@ bool UI_context_copy_to_selected_list(bContext *C, static bool copy_to_selected_button(bContext *C, bool all, bool poll) { Main *bmain = CTX_data_main(C); - PointerRNA ptr, lptr, idptr; + PointerRNA ptr, lptr; PropertyRNA *prop, *lprop; bool success = false; int index; @@ -1019,32 +1117,8 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll) continue; } - if (use_path_from_id) { - /* Path relative to ID. */ - lprop = NULL; - RNA_id_pointer_create(link->ptr.owner_id, &idptr); - RNA_path_resolve_property(&idptr, path, &lptr, &lprop); - } - else if (path) { - /* Path relative to elements from list. */ - lprop = NULL; - RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); - } - else { - lptr = link->ptr; - lprop = prop; - } - - if (lptr.data == ptr.data) { - /* lptr might not be the same as link->ptr! */ - continue; - } - - if (lprop != prop) { - continue; - } - - if (!RNA_property_editable(&lptr, lprop)) { + if (!UI_context_copy_to_selected_check( + &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) { continue; } @@ -1337,10 +1411,6 @@ void UI_editsource_active_but_test(uiBut *but) BLI_ghash_insert(ui_editsource_info->hash, but, but_store); } -/** - * Remove the editsource data for \a old_but and reinsert it for \a new_but. Use when the button - * was reallocated, e.g. to have a new type (#ui_but_change_type()). - */ void UI_editsource_but_replace(const uiBut *old_but, uiBut *new_but) { uiEditSourceButStore *but_store = BLI_ghash_lookup(ui_editsource_info->hash, old_but); @@ -1402,7 +1472,7 @@ static int editsource_exec(bContext *C, wmOperator *op) int ret; /* needed else the active button does not get tested */ - UI_screen_free_active_but(C, CTX_wm_screen(C)); + UI_screen_free_active_but_highlight(C, CTX_wm_screen(C)); // printf("%s: begin\n", __func__); @@ -1683,8 +1753,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev bScreen *screen = CTX_wm_screen(C); const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed"); ARegion *region_prev = CTX_wm_region(C); - ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->x, event->y) : - NULL; + ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : NULL; if (region == NULL) { region = region_prev; @@ -1860,6 +1929,39 @@ static void UI_OT_drop_color(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Drop Name Operator + * \{ */ + +static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + uiBut *but = UI_but_active_drop_name_button(C); + char *str = RNA_string_get_alloc(op->ptr, "string", NULL, 0, NULL); + + if (str) { + ui_but_set_string_interactive(C, but, str); + MEM_freeN(str); + } + + return OPERATOR_FINISHED; +} + +static void UI_OT_drop_name(wmOperatorType *ot) +{ + ot->name = "Drop Name"; + ot->idname = "UI_OT_drop_name"; + ot->description = "Drop name to button"; + + ot->poll = ED_operator_regionactive; + ot->invoke = drop_name_invoke; + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + + RNA_def_string( + ot->srna, "string", NULL, 0, "String", "The string value to drop into the button"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name UI List Search Operator * \{ */ @@ -1918,6 +2020,93 @@ static void UI_OT_list_start_filter(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name UI Tree-View Drop Operator + * \{ */ + +static bool ui_tree_view_drop_poll(bContext *C) +{ + const wmWindow *win = CTX_wm_window(C); + const ARegion *region = CTX_wm_region(C); + const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at( + region, win->eventstate->xy); + + return hovered_tree_item != NULL; +} + +static int ui_tree_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + if (event->custom != EVT_DATA_DRAGDROP) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + } + + const ARegion *region = CTX_wm_region(C); + uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, event->xy); + + if (!UI_tree_view_item_drop_handle(C, hovered_tree_item, event->customdata)) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + } + + return OPERATOR_FINISHED; +} + +static void UI_OT_tree_view_drop(wmOperatorType *ot) +{ + ot->name = "Tree View drop"; + ot->idname = "UI_OT_tree_view_drop"; + ot->description = "Drag and drop items onto a tree item"; + + ot->invoke = ui_tree_view_drop_invoke; + ot->poll = ui_tree_view_drop_poll; + + ot->flag = OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name UI Tree-View Item Rename Operator + * + * General purpose renaming operator for tree-views. Thanks to this, to add a rename button to + * context menus for example, tree-view API users don't have to implement own renaming operators + * with the same logic as they already have for their #ui::AbstractTreeViewItem::rename() override. + * + * \{ */ + +static bool ui_tree_view_item_rename_poll(bContext *C) +{ + const ARegion *region = CTX_wm_region(C); + const uiTreeViewItemHandle *active_item = UI_block_tree_view_find_active_item(region); + return active_item != NULL && UI_tree_view_item_can_rename(active_item); +} + +static int ui_tree_view_item_rename_exec(bContext *C, wmOperator *UNUSED(op)) +{ + ARegion *region = CTX_wm_region(C); + uiTreeViewItemHandle *active_item = UI_block_tree_view_find_active_item(region); + + UI_tree_view_item_begin_rename(active_item); + ED_region_tag_redraw(region); + + return OPERATOR_FINISHED; +} + +static void UI_OT_tree_view_item_rename(wmOperatorType *ot) +{ + ot->name = "Rename Tree-View Item"; + ot->idname = "UI_OT_tree_view_item_rename"; + ot->description = "Rename the active item in the tree"; + + ot->exec = ui_tree_view_item_rename_exec; + ot->poll = ui_tree_view_item_rename_poll; + /* Could get a custom tooltip via the `get_description()` callback and another overridable + * function of the tree-view. */ + + ot->flag = OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Operator & Keymap Registration * \{ */ @@ -1934,6 +2123,7 @@ void ED_operatortypes_ui(void) WM_operatortype_append(UI_OT_copy_to_selected_button); WM_operatortype_append(UI_OT_jump_to_target_button); WM_operatortype_append(UI_OT_drop_color); + WM_operatortype_append(UI_OT_drop_name); #ifdef WITH_PYTHON WM_operatortype_append(UI_OT_editsource); WM_operatortype_append(UI_OT_edittranslation_init); @@ -1944,6 +2134,9 @@ void ED_operatortypes_ui(void) WM_operatortype_append(UI_OT_list_start_filter); + WM_operatortype_append(UI_OT_tree_view_drop); + WM_operatortype_append(UI_OT_tree_view_item_rename); + /* external */ WM_operatortype_append(UI_OT_eyedropper_color); WM_operatortype_append(UI_OT_eyedropper_colorramp); @@ -1954,9 +2147,6 @@ void ED_operatortypes_ui(void) WM_operatortype_append(UI_OT_eyedropper_gpencil_color); } -/** - * \brief User Interface Keymap - */ void ED_keymap_ui(wmKeyConfig *keyconf) { WM_keymap_ensure(keyconf, "User Interface", 0, 0); |