4
$\begingroup$

Given this simple example, if you call foo.bar directly (e.g. via F3 search menu) the float property X is remembered between subsequent calls. However, when invoked via a hotkey (e.g. activate foo tool and then press Shift+R) the property X resets to the default value (0).

It seems similar to this previous question though apparently it's a fixed bug so not sure if this is something different.

As a bonus, I also draw a non operator property, and wonder why you cannot change this value?

import bpy

class Fooprop(bpy.types.PropertyGroup):
    x: bpy.props.FloatProperty(name="X", default=0.5)

class Foobar(bpy.types.Operator):
    bl_idname = "foo.bar"
    bl_label = "Foobar"
    bl_options = {"REGISTER", "UNDO"}
    x: bpy.props.FloatProperty(name="X")

    def execute(self, context):
        return {"FINISHED"}

    def draw(self, context):
        row = self.layout.row()
        row.prop(self, "x")
        row.prop(context.scene.Fooprop, "x")

    def invoke(self, context, event):
        return self.execute(context)

class FooTool(bpy.types.WorkSpaceTool):
    bl_space_type = "VIEW_3D"
    bl_label = "FooTool"
    bl_context_mode = "OBJECT"

    bl_idname = "foo.bar_tool"
    bl_widget = None
    bl_keymap = (("foo.bar", {"type": "R", "value": "PRESS", "shift": True}, {"properties": []}),)

bpy.utils.register_class(Foobar)
bpy.utils.register_class(Fooprop)
bpy.types.Scene.Fooprop = bpy.props.PointerProperty(type=Fooprop)
bpy.utils.register_tool(FooTool, after={"builtin.scale_cage"}, separator=True, group=True)
```
$\endgroup$

1 Answer 1

3
$\begingroup$

After a bit of digging I found out the operator keymaps can't remember their previousy used property values because they are driven by another value, directly in the keymap entry inside the preferences.

enter image description here

In order to change the default property value, the user can tweak the properties fields, which are greyed out by default

enter image description here

The purpose of such a system is AFAIU to let the user setup shortcuts for calling operators with specific values. One operator can be associated to many keymaps, with varying property default values.

Here's a hacky workaround you can use to change the default value of the operator inside the preferences every time the operator is executed. However this will permanently change this value, instead of how it works with regular operator calls.

import bpy

def remember_tool_properties(context):
    operator = context.active_operator
    wm = context.window_manager
    keyconfigs = wm.keyconfigs
    kmi = keyconfigs.find_item_from_operator(operator.bl_idname)[1]
    for attr in operator.properties.keys():
        setattr(kmi.properties, attr, getattr(operator, attr))
    

class Fooprop(bpy.types.PropertyGroup):
    x: bpy.props.FloatProperty(name="X", default=0.5)


class Foobar(bpy.types.Operator):
    bl_idname = "foo.bar"
    bl_label = "Foobar"
    bl_options = {"REGISTER", "UNDO"}
    x: bpy.props.FloatProperty(name="X")

    def execute(self, context):
        remember_tool_properties(context)
        return {"FINISHED"}

    def draw(self, context):
        row = self.layout.row()
        row.prop(self, "x")
        row.prop(context.scene.Fooprop, "x")


class FooTool(bpy.types.WorkSpaceTool):
    bl_space_type = "VIEW_3D"
    bl_label = "FooTool"
    bl_context_mode = "OBJECT"

    bl_idname = "foo.bar_tool"
    bl_widget = None
    bl_keymap = (("foo.bar", {"type": "R", "value": "PRESS", "shift": True}, {"properties": []}),)


bpy.utils.register_class(Foobar)
bpy.utils.register_class(Fooprop)
bpy.types.Scene.Fooprop = bpy.props.PointerProperty(type=Fooprop)
try:
    bpy.utils.register_tool(FooTool, after={"builtin.scale_cage"}, separator=True, group=True)
except Exception:
    pass

enter image description here

One could implement a callback when the file is opened to reset this value to default to imitate default behavior. I wouldn't recommend doing it on closing the file because it can be terminated by a crash which would prevent the code from running.

And for your second question, I don't think it is intended to be able to tweak values that are outside the scope of an operator's properties inside an operator's draw method. It might lead to unintended consequences, for instance rendering the poll method return value False which would be forbidden.

According the the docs this method is intended to re-order the operators as you like, not really to tweak other properties outside of its scope.

Sources :

bpy.types.KeyConfigurations.find_item_from_operator

https://devtalk.blender.org/t/python-how-do-i-access-keymap-entries-from-the-new-tool-system/19295

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .