1
$\begingroup$

I have a self made checkbox in a script. Now I want to create a hotkey in the Input manager to toggle it.

What I have done so far is to create a keymap item with wm.context_toggle. But I cannot get the Context Attribute to work. I grab the one from my script, the Python term in the tooltip. Which is WindowManager.deselect_bool and with that I get an error that the "Object has no attribute WindowManager".

What is the proper Context Attribute term here? Is it even possible to do it this way? If not, what is the proper way to assign a toggle hotkey for my custom checkbox?

Script:

import bpy
from bpy.props import BoolProperty

class LayoutDemoPanel(bpy.types.Panel):
    bl_label = "Demo Panel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'

    def draw(self, context):
        layout = self.layout

        wm = context.window_manager # Our bool is in the windows_manager
        layout.prop(wm, "deselect_bool") # Our checkbox

def register():
    bpy.types.WindowManager.deselect_bool = bpy.props.BoolProperty(
    name="Checkbox", description="A checkbox", default = False)
    bpy.utils.register_module(__name__)

def unregister():
    del bpy.types.WindowManager.deselect_bool # Unregister our flag when unregister.
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()

enter image description here

$\endgroup$
  • 1
    $\begingroup$ The context attribute would be window_ manager.deselect_bool WindowManager is the class of context.window_manager Look in system console for error messages. $\endgroup$ – batFINGER Jul 23 '16 at 16:48
  • $\begingroup$ @batFINGER, thanks, but i get just another error message now, SyntaxError: invalid syntax. And no hint where. location: :-1 $\endgroup$ – Tiles Jul 23 '16 at 17:14
  • 1
    $\begingroup$ batFINGERs suggestion works for me when using your script, are you sure you don't have a typo somewhere? One thing that's strange however: The hotkey does work, but the checkbox is updated only if you put the mouse cursor into the panel where it lives in. Not sure if that really is the way to go $\endgroup$ – aliasguru Jul 23 '16 at 18:42
  • $\begingroup$ That's odd. I have copied and pasted the terms to avoid typoes. And as told, i get the upper error when i have the mouse over the 3D view. But thanks for your observation. When i have the mouse over the panel then i don't get the error message. But the checkbox doesn't toggle neither, which it does for you. What do we overlook here? $\endgroup$ – Tiles Jul 23 '16 at 18:59
  • $\begingroup$ Ah, wasn't a good idea to copy the term from batFINGER's post. He had a gap in window_ manager. When i write window_manager then the error is gone. But still no toggle with the hotkey :( $\endgroup$ – Tiles Jul 23 '16 at 19:02
4
$\begingroup$

Here is an example based on this answer. Once it's registered you can press ShiftQ to toggle your BoolProperty. Also notice that tagging the area for a redraw via context.area.tag_redraw() is requiered after the assignment call in oder to update the Panel properly:

enter image description here

Once it's enabled (or registered) the shortcut is created automatically:

enter image description here

custom-toggle-shortcut.py

bl_info = {
    "name": "Add-on Template",
    "description": "",
    "author": "poor",
    "version": (0, 0, 1),
    "blender": (2, 70, 0),
    "location": "3D View > Tools",
    "warning": "", # used for warning icon and text in addons panel
    "wiki_url": "",
    "tracker_url": "",
    "category": "Development"
}

import bpy

# ------------------------------------------------------------------------
#    my properties
# ------------------------------------------------------------------------

class MySettings(bpy.types.PropertyGroup):

    my_bool = bpy.props.BoolProperty(
        name="Enable or Disable",
        description="A bool property",
        default = False
        )

# ------------------------------------------------------------------------
#    operators
# ------------------------------------------------------------------------

class ToggleOperator(bpy.types.Operator):
    bl_idname = "view3d.toggle_mybool"
    bl_label = "Toggle My Bool"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):  
        context.scene.my_tool.my_bool = not context.scene.my_tool.my_bool
        context.area.tag_redraw()
        return {'FINISHED'}


# ------------------------------------------------------------------------
#    my tool in objectmode
# ------------------------------------------------------------------------

class OBJECT_PT_my_panel(bpy.types.Panel):
    bl_idname = "OBJECT_PT_my_panel"
    bl_label = "My Panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"    
    bl_context = "objectmode"   

    @classmethod
    def poll(self,context):
        return context.object is not None

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool
        layout.prop(mytool, "my_bool")

# ------------------------------------------------------------------------
#     register and unregister
# ------------------------------------------------------------------------

addon_keymaps = []

def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.my_tool = bpy.props.PointerProperty(type=MySettings)

    # handle the keymap
    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc:
        km = wm.keyconfigs.addon.keymaps.new(name='3D View', space_type='VIEW_3D')
        kmi = km.keymap_items.new(ToggleOperator.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_module(__name__)
    del bpy.types.Scene.my_tool


if __name__ == "__main__":
    register()

Gist: https://gist.github.com/p2or/8a37617c4565e4ff143b736a0e4a1660

Alternatively using an update method

Rather than create a new operator use the wm.context_toggle operator, and set up an update method on the property that will redraw the area when run. If the panel is in same area as key press then would only need update=prop_update

def prop_update(self, context):
    context.area.tag_redraw()
    return None

In example below area_ui_update('VIEW_3D') returns an update method where if area.type == 'VIEW_3D' in screen.areas that area will redraw. Useful when your panel is in an area other than context.area eg if your panel was in 'PROPERTIES' you would area_ui_update('PROPERTIES')

import bpy

def area_ui_update(type):
    ''' tag redraw on areas of type '''
    def ui_update(self, context):
        areas = [a for a in screen.areas if a.type == type]
        for a in areas:
            area.tag_redraw()
        return None
    return ui_update

class MySettings(bpy.types.PropertyGroup):

    my_bool = bpy.props.BoolProperty(
        name="Enable or Disable",
        description="A bool property",
        default = False,
        update=area_ui_update('VIEW_3D')
        )

# ------------------------------------------------------------------------
#    my tool in objectmode
# ------------------------------------------------------------------------

class OBJECT_PT_my_panel(bpy.types.Panel):
    bl_idname = "OBJECT_PT_my_panel"
    bl_label = "My Panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"    
    bl_context = "objectmode"   

    @classmethod
    def poll(self,context):
        return context.object is not None

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool

        layout.prop(mytool, "my_bool")

# ------------------------------------------------------------------------
# register and unregister
# ------------------------------------------------------------------------

addon_keymaps = []

# register
def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.my_tool = bpy.props.PointerProperty(type=MySettings)

    # handle the keymap
    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc:
        km = wm.keyconfigs.addon.keymaps.new(name='3D View', space_type='VIEW_3D')
        kmi = km.keymap_items.new("wm.context_toggle", type='Q', value='PRESS', shift=True)
        kmi.properties.data_path = "scene.my_tool.my_bool"
        addon_keymaps.append((km, kmi))

# unregister
def unregister():

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

    bpy.utils.unregister_module(__name__)
    del bpy.types.Scene.my_tool


if __name__ == "__main__":
    register()
$\endgroup$
  • $\begingroup$ Hope you like new addition. $\endgroup$ – batFINGER Jul 25 '16 at 7:53
  • $\begingroup$ Very much. I'm still at investigating. Thank you both :) $\endgroup$ – Tiles Jul 25 '16 at 8:16
  • $\begingroup$ One small problem is left. The Info editor does not display the changes to the bool. That happens just when you click the checkbox. Any ideas here? :) $\endgroup$ – Tiles Jul 26 '16 at 8:42
  • 1
    $\begingroup$ @Tiles That's normal behavior. Reflecting a bool change in the info area, only works when clicking a property or calling an operator. You can test this by your own - assign a shortcut to a existent bool property and you'll see that nothing shows up. Again, for simplicity I suggest use my Add-on template. You will see that the operator call shows up in the info area. Alternatively you can report any change in the info area, I updated the gist: gist.github.com/p2or/8a37617c4565e4ff143b736a0e4a1660, see line 43 and 46. More info here: blender.stackexchange.com/q/717/3710 $\endgroup$ – p2or Jul 26 '16 at 10:34
  • 1
    $\begingroup$ Perfect. Now we have really everything :) $\endgroup$ – Tiles Jul 26 '16 at 10:56
-1
$\begingroup$

The answer from batFINGER was the solution for the intial problem:

The context attribute would be window_manager.deselect_bool WindowManager is the class of context.window_manager Look in system console for error messages. – batFINGER

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.