Page MenuHome

API - optional full_path parameter for bpy.ops.ui.copy_data_path_button()
ClosedPublic

Authored by Christian Brinkmann (poor) on Oct 15 2016, 8:38 PM.

Details

Summary

This simple patch adds a full_path parameter to copy_data_path_button() operator in order to match the behavior of Ctrl+Shift+Alt+C shortcut on the active mouse cursor property, which isn't exposed to the API yet.


At the moment the operator copies the data-path of the active mouse cursor UI property to the clipboard. By placing the cursor over the scenes 'resolution x' property and running copy_data_path_button() the clipboard yields: render.resolution_x. However in order to find the corresponding RNA path via python an entire RNA iteration is required (error-prone and slow). By using this patch and setting full_path flag to True, the operator now allows to copy the full data-path of the data-block to the clipboard so in this case: bpy.data.scenes["Scene"].render.resolution_x and is especially fast as expected.


For demonstration purposes as well as to provide a simple use case I wrote a python operator to report the active property when pressing Shift+Q while mouse cursor is over a UI property (to test the assignment it also adds 1 to the value of each IntegerProperty or FloatProperty per execution).

import bpy

class MouseCursorPropertyOperator(bpy.types.Operator):
    bl_idname = "screen.active_property_add"
    bl_label = "Add custom value to active mouse cursor property"
    bl_options = {'REGISTER'}
    
    @classmethod
    def poll(cls, context):
        return bpy.ops.ui.copy_data_path_button.poll()

    def execute(self, context):      
        
        # get the data path
        bpy.ops.ui.copy_data_path_button()
        path = context.window_manager.clipboard
        
        # get full data path
        bpy.ops.ui.copy_data_path_button(full_path=True)
        full_path = context.window_manager.clipboard
        
        # split path in class and property
        rna, prop = context.window_manager.clipboard.rsplit('.', 1)
        addend = 1
        
        # set attribute value if its type is an integer
        if type(eval(full_path)) is int:
            rna_eval = (eval(rna))
            value = getattr(rna_eval, prop)
            setattr(rna_eval, prop, value + addend)
            self.report({"INFO"}, "{} set to {}".format(prop, value + addend))
        
        # set attribute value if its type is an float
        elif type(eval(full_path)) is float:
            if prop.endswith("]"): # check if property is vector
                #print (getattr(rna_eval, path))
                index = prop[-2:-1] 
                rna_eval = eval(".".join([rna, path]))
                value = getattr(rna_eval, ("x","y","z")[int(index)])
                setattr(rna_eval, ("x","y","z")[int(index)], value + addend)
                self.report({"INFO"}, "{} set to {}".format(prop, value + addend))
            else: # single float property
                rna_eval = (eval(rna))
                value = getattr(rna_eval, prop)
                setattr(rna_eval, prop, value + 10)
                self.report({"INFO"}, "{} set to {}".format(prop, value + addend))
        
        # neither integer nor float
        else:
            print (type(eval(full_path)))
            self.report({"INFO"}, "{} not an integer or float".format(prop))

        return {'FINISHED'}


addon_keymaps = []

def register():
    bpy.utils.register_class(MouseCursorPropertyOperator)

    # handle the keymap
    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc:
        km = wm.keyconfigs.addon.keymaps.new(name='Screen')
        kmi = km.keymap_items.new(MouseCursorPropertyOperator.bl_idname, type='Q', value='PRESS', shift=True)
        addon_keymaps.append((km, kmi))

def unregister():

    for km, kmi in addon_keymaps:
        km.keymap_items.remove(kmi)
    addon_keymaps.clear()

    bpy.utils.unregister_class(MouseCursorPropertyOperator)


if __name__ == "__main__":
    register()

Here a gif: https://i.stack.imgur.com/Qd6YS.gif

Note: Unfortunately it does not work in the compositor for this reason.

Best regards,
Christian

Diff Detail

Repository
rB Blender

Event Timeline

Christian Brinkmann (poor) retitled this revision from to API - optional full_path parameter for bpy.ops.ui.copy_data_path_button().
Christian Brinkmann (poor) updated this object.
Christian Brinkmann (poor) set the repository for this revision to rB Blender.
Brecht Van Lommel (brecht) requested changes to this revision.Oct 16 2016, 4:00 PM

This is different than the implementation in ui_but_copy_data_path(), we should at least make it consistent.

if (full_path) {
    if (but->rnaprop) {
        id_path = RNA_path_full_property_py_ex(&but->rnapoin, but->rnaprop, but->rnaindex, true);
    }
    else {
        id_path = RNA_path_full_struct_py(&but->rnapoin);
    }
}
else {
    id_path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
}

Even better would be to deduplicate code and remove ui_but_copy_data_path() entirely, and instead add this operator in ED_keymap_ui().

This revision now requires changes to proceed.Oct 16 2016, 4:00 PM
Christian Brinkmann (poor) edited edge metadata.
Christian Brinkmann (poor) removed rB Blender as the repository for this revision.

Consistency approach to match the behavior of ui_but_copy_data_path() in interface_handlers.c.

Thanks for your review @Brecht Van Lommel (brecht)! I've updated the code in order to match ui_but_copy_data_path().

Even better would be to deduplicate code and remove ui_but_copy_data_path() entirely, and instead add this operator in ED_keymap_ui().

Great idea!

I've already tried removing ui_but_copy_data_path() and adding UI_OT_copy_data_path_button operator via WM_keymap_add_item(keymap, "UI_OT_copy_data_path_button", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT | KM_ALT, 0); to the keymap instead. The shortcut registers as expected:

But unfortunately something seems to block it from the execution and I can't really figure out what it is. Also I'm not sure how to add the second shortcut with its positional argument correctly.

Do you may have any advice? Thanks again!

I'm not sure how you modified the UI handling code, but probably it's swallowing the event still while it should be passing it on. I expect this to work:

--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -6985,7 +6985,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
        if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) {
                /* handle copy-paste */
                if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS &&
-                   IS_EVENT_MOD(event, ctrl, oskey))
+                   IS_EVENT_MOD(event, ctrl, oskey) && !event->shift && !event->alt)
                {
                        /* Specific handling for listrows, we try to find their overlapping tex button. */
                        if (but->type == UI_BTYPE_LISTROW) {
@@ -6996,12 +6996,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
                                }
                        }

-                       /* special case, copy-data-path */
-                       if ((event->type == CKEY) && event->shift) {
-                               ui_but_copy_data_path(but, event->alt != 0);
-                               return WM_UI_HANDLER_BREAK;
-                       }
-
                        ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v');
                        return WM_UI_HANDLER_BREAK;
                }

ui_but_copy_data_path() removed and its functionality exposed to copy_data_path_button() operator

I'm not sure how you modified the UI handling code, but probably it's swallowing the event still while it should be passing it on.

Brilliant! Thanks @Brecht Van Lommel (brecht).


As you suggested ui_but_copy_data_path() is fully exposed to copy_data_path_button() operator now. Both shortcuts are registered properly, the right-click menu now shows the shortcut of Copy Data Path and its execution is also working as expected.

Brecht Van Lommel (brecht) edited edge metadata.

Looks good to me.

This revision is now accepted and ready to land.Oct 20 2016, 12:26 AM
This revision was automatically updated to reflect the committed changes.