Beispiel #1
0
    def draw(self, context):
        from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
        layout = self.layout

        tool_settings = context.tool_settings
        ToolSelectPanelHelper.draw_fallback_tool_items(layout, context)
        if tool_settings.workspace_tool_type == 'FALLBACK':
            tool = context.tool
            ToolSelectPanelHelper.draw_active_tool_fallback(context, layout, tool)
Beispiel #2
0
    def draw(self, context):
        from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
        layout = self.layout

        # Get the active tool
        space_type, mode = ToolSelectPanelHelper._tool_key_from_context(
            context)
        cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
        item, tool, _ = cls._tool_get_active(
            context, space_type, mode, with_icon=True)
        if item is None:
            return

        # Draw the extra settings
        item.draw_settings(context, layout, tool, extra=True)
Beispiel #3
0
    def invoke(self, context, event):
        dofu = context.scene.dof_utils  #context.area.tag_redraw()
        prefs = context.preferences.addons[__name__].preferences

        if not dofu.use_cursor:
            if context.space_data.type == 'VIEW_3D':

                # Get the current active tool
                from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
                self._tool = ToolSelectPanelHelper.tool_active_from_context(
                    context).idname

                if prefs.display_info and not DofUtilsSettings._instructions_handle:
                    args = (self, context)
                    DofUtilsSettings._instructions_handle = bpy.types.SpaceView3D.draw_handler_add(
                        draw_callback_2d, args, 'WINDOW', 'POST_PIXEL')

                context.window_manager.modal_handler_add(self)
                dofu.use_cursor = True
                return {'RUNNING_MODAL'}
            else:
                self.report({'WARNING'},
                            "View3D not found, cannot run operator")
                return {'CANCELLED'}
        else:
            self.report({'WARNING'}, "Operator is already running")
            return {'CANCELLED'}
Beispiel #4
0
    def draw_tool_settings(self, context):
        layout = self.layout

        # Active Tool
        # -----------
        from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
        tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout)
        tool_mode = context.mode if tool is None else tool.mode

        # Object Mode Options
        # -------------------

        # Example of how tool_settings can be accessed as pop-overs.

        # TODO(campbell): editing options should be after active tool options
        # (obviously separated for from the users POV)
        draw_fn = getattr(_draw_tool_settings_context_mode, tool_mode, None)
        if draw_fn is not None:
            draw_fn(context, layout, tool)

        if tool_mode == 'PAINT':
            if (tool is not None) and tool.has_datablock:
                layout.popover("IMAGE_PT_paint_settings_advanced")
                layout.popover("IMAGE_PT_paint_stroke")
                layout.popover("IMAGE_PT_paint_curve")
                layout.popover("IMAGE_PT_tools_brush_display")
                layout.popover("IMAGE_PT_tools_brush_texture")
                layout.popover("IMAGE_PT_tools_mask_texture")
        elif tool_mode == 'UV':
            if (tool is not None) and tool.has_datablock:
                layout.popover("IMAGE_PT_uv_sculpt_curve")
                layout.popover("IMAGE_PT_uv_sculpt_options")
Beispiel #5
0
    def invoke(self, context, event):

        current_tool = ToolSelectPanelHelper._tool_get_active(
            context, 'VIEW_3D', None)[0][0]
        self.current_tool = current_tool
        if current_tool != "BoxCutter":
            bpy.ops.wm.tool_set_by_id(name="builtin.select",
                                      space_type='VIEW_3D')

        if context.space_data.type == 'VIEW_3D':
            wm = context.window_manager
            wm.gizmo_group_type_ensure(HOPS_OT_HopsArrayGizmoGroup.bl_idname)

        get_preferences().Hops_gizmo = True
        if context.space_data.type == 'VIEW_3D':
            get_preferences().Hops_gizmo_mirror = True
            context.area.tag_redraw()

        ob = context.active_object
        array = get_modifier_with_type(ob, "ARRAY")
        if array is not None:
            if array.name == "Array":
                if array.use_relative_offset:

                    dimensions_x = ob.dimensions[0] / (abs(
                        ob.modifiers["Array"].relative_offset_displace[0]) *
                                                       (array.count - 1) + 1)
                    dimensions_y = ob.dimensions[1] / (abs(
                        ob.modifiers["Array"].relative_offset_displace[1]) *
                                                       (array.count - 1) + 1)
                    dimensions_z = ob.dimensions[2] / (abs(
                        ob.modifiers["Array"].relative_offset_displace[2]) *
                                                       (array.count - 1) + 1)

                    ob.hops.array_x = dimensions_x * ob.modifiers[
                        "Array"].relative_offset_displace[0]
                    ob.hops.array_y = dimensions_y * ob.modifiers[
                        "Array"].relative_offset_displace[1]
                    ob.hops.array_z = dimensions_z * ob.modifiers[
                        "Array"].relative_offset_displace[2]

                else:

                    ob.hops.array_x = ob.modifiers[
                        "Array"].constant_offset_displace[0]
                    ob.hops.array_y = ob.modifiers[
                        "Array"].constant_offset_displace[1]
                    ob.hops.array_z = ob.modifiers[
                        "Array"].constant_offset_displace[2]

        # bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
        # self.draw_handler = bpy.types.SpaceView3D.draw_handler_add(self.draw_ui, (context, ), "HEADER", "POST_PIXEL")
        context.area.header_text_set("Hardops Array    Add Array Modifier")
        context.window_manager.modal_handler_add(self)
        return {"RUNNING_MODAL"}
Beispiel #6
0
def reset_active_tool():
    for workspace in bpy.data.workspaces:
        for screen in workspace.screens:
            for area in screen.areas:
                if area.type == 'VIEW_3D':
                    override = {"screen": screen, "area": area, "space_data": area.spaces[0]}
                    bpy.ops.wm.tool_set_by_id(override, name="builtin.select_box")

    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
    cls = ToolSelectPanelHelper._tool_class_from_space_type('VIEW_3D')
    cls._tool_group_active = {"bultin.select": 1}
Beispiel #7
0
    def draw_mode_settings(self, context):
        layout = self.layout

        # Active Tool
        # -----------
        from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
        tool = ToolSelectPanelHelper.tool_active_from_context(context)
        tool_mode = context.mode if tool is None else tool.mode

        if tool_mode == 'PAINT':
            layout.popover_group(space_type='IMAGE_EDITOR', region_type='UI', context=".imagepaint_2d", category="")
Beispiel #8
0
    def invoke(self, context, event):
        current_tool = ToolSelectPanelHelper._tool_get_active(
            context, 'VIEW_3D', None)[0][0]

        if current_tool == 'BoxCutter':
            return {'PASS_THROUGH'}

        else:
            context.window_manager.decal_mousepos = (event.mouse_region_x,
                                                     event.mouse_region_y)

            bpy.ops.wm.call_menu_pie(name='MACHIN3_MT_%s' % (self.idname))
            return {'FINISHED'}
Beispiel #9
0
def unregister():
    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper

    modes = ('OBJECT', 'EDIT_MESH')
    space_type = 'VIEW_3D'

    for context_mode in modes:
        cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)

        tools = cls._tools[context_mode]
        tools.remove(boxcutter)

        if tools[-1] == None:
            del tools[-1]
Beispiel #10
0
def register():
    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
    from bl_keymap_utils.io import keyconfig_init_from_data

    modes = ('OBJECT', 'EDIT_MESH')
    space_type = 'VIEW_3D'

    for context_mode in modes:
        view3d_tools._tools[context_mode].append(None)

        cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)

        tools = cls._tools[context_mode]
        tools.append(boxcutter)
Beispiel #11
0
def unregister_tool(space_type, context_mode, tool_def):
    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
    if cls is None:
        raise Exception(f"Space type {space_type!r} has no toolbar")
    tools = cls._tools[context_mode]
    tools.remove(tool_def)

    keymap_data = tool_def.keymap
    if keymap_data is not None:
        from bpy import context
        wm = context.window_manager
        kc = wm.keyconfigs.default
        km = keymap_data[0]
        kc.keymaps.remove(km)
Beispiel #12
0
    def invoke(self, context, event):
        current_tool = ToolSelectPanelHelper._tool_get_active(context, 'VIEW_3D', None)[0][0]

        if current_tool == 'BoxCutter':
            return {'PASS_THROUGH'}

        else:
            op = getattr(bpy.ops.machin3, self.idname, None)

            if op:
                if self.isinvoke:
                    op('INVOKE_DEFAULT')

                else:
                    op()

        return {'FINISHED'}
Beispiel #13
0
    def invoke(self, context, event):
        # reset decalmode, if it's NONE (the AddDecalToLibrary tool, if aborted, leaves it in this state)
        if get_prefs().decalmode == "NONE":
            get_prefs().decalmode = "INSERT"
            get_prefs().decalremovemode = False

        current_tool = ToolSelectPanelHelper._tool_get_active(
            context, 'VIEW_3D', None)[0][0]

        if current_tool == 'BoxCutter':
            return {'PASS_THROUGH'}

        else:
            context.window_manager.decal_mousepos = (event.mouse_region_x,
                                                     event.mouse_region_y)

            bpy.ops.wm.call_menu_pie(name='MACHIN3_MT_%s' % (self.idname))
            return {'FINISHED'}
Beispiel #14
0
    def draw(self, context):
        layout = self.layout

        # Active Tool
        # -----------
        from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
        tool = ToolSelectPanelHelper.tool_active_from_context(context)
#       print(tool.idname)
        props = tool.operator_properties("mesh.poly_quilt")
        preferences = bpy.context.preferences.addons[__package__].preferences

        col = layout.column()        
        col.label( text = "Pivot" )
        col.prop(props, "plane_pivot" , text = "Pivot" , expand = True )

        col = layout.column()        
        col.label( text = "Move" )
        row = layout.row()           
        row.ui_units_x = 3.25     
        row.prop(props, "move_type" , text = "" , expand = True , icon_only = True )
  
        col = layout.column()        
        col.label( text = "Snap" )
        row = layout.row(align=True)
        row.prop(props, "snap_mode" , text = "Snap" , expand = True , icon_only = False )

        layout.label( text = "Fix X=0" )
        layout.prop( preferences, "fix_to_x_zero", toggle = True , text = "" , icon_only = True, icon_value = custom_icon("icon_opt_x0") )

        layout.label( text = "Extrude" )
        layout.prop(props, "extrude_mode" , text = "EXTRUDE" , expand = True )

        layout.label( text = "LOOPCUT" )
        layout.prop(props, "loopcut_mode" , text = "LOOPCUT" , expand = True )
        col = layout.column()              
        col.label( text = "Edge Snap Div" )        
        col.prop( preferences, "loopcut_division" , text = "Edge Snap Div" , expand = True, slider = True , icon_only = False )

        col.label( text = "Vertex Dissolve Angle" )        
        col.prop( preferences, "vertex_dissolve_angle" , text = "Vertex Dissolve Angle", expand = True, slider = True , icon_only = False  )

        col.label( text = "Brush" )        
        col.prop( preferences, "brush_size" , text = "Brush Size" , expand = True, slider = True , icon_only = False )
        col.prop( preferences, "brush_strength" , text = "Brush Strength" , expand = True, slider = True , icon_only = False )
Beispiel #15
0
    def invoke(self, context, event):
        current_tool = ToolSelectPanelHelper._tool_get_active(
            context, 'VIEW_3D', None)[0][0]
        self.current_tool = current_tool
        if current_tool != "BoxCutter":
            bpy.ops.wm.tool_set_by_id(name="builtin.select",
                                      space_type='VIEW_3D')

        if context.space_data.type == 'VIEW_3D':
            wm = context.window_manager
            wm.gizmo_group_type_ensure(HOPS_OT_MirrorGizmoGroup.bl_idname)

        get_preferences().Hops_gizmo = True
        if context.space_data.type == 'VIEW_3D':
            context.area.tag_redraw()

        context.area.header_text_set("Hardops Mirror")
        context.window_manager.modal_handler_add(self)
        return {"RUNNING_MODAL"}
Beispiel #16
0
def register_tool(space_type, context_mode, tool_def):
    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
    if cls is None:
        raise Exception(f"Space type {space_type!r} has no toolbar")
    tools = cls._tools[context_mode]

    keymap_data = tool_def.keymap
    if keymap_data is not None:
        if context_mode is None:
            context_descr = "All"
        else:
            context_descr = context_mode.replace("_", " ").title()
        from bpy import context
        wm = context.window_manager
        kc = wm.keyconfigs.default
        if callable(keymap_data[0]):
            cls._km_action_simple(kc, context_descr, tool_def.text,
                                  keymap_data)

    tools.append(tool_def)
    def get_brush_mode(context):
        """ Get the correct mode for this context. For any context where this returns None,
            no brush options should be displayed."""

        if context.mode == 'PARTICLE':
            # Particle brush settings currently completely do their own thing.
            return None

        from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
        tool = ToolSelectPanelHelper.tool_active_from_context(context)

        if not tool:
            # If there is no active tool, then there can't be an active brush.
            return None

        if not tool.has_datablock:
            # tool.has_datablock is always true for tools that use brushes.
            return None

        space_data = context.space_data
        tool_settings = context.tool_settings

        if space_data:
            space_type = space_data.type
            if space_type == 'IMAGE_EDITOR':
                if space_data.show_uvedit:
                    return 'UV_SCULPT'
                return 'PAINT_2D'

            if space_type in {'VIEW_3D', 'PROPERTIES'}:
                if context.mode == 'PAINT_TEXTURE':
                    if tool_settings.image_paint and tool_settings.image_paint.detect_data(
                    ):
                        return context.mode
                    else:
                        return None
                return context.mode
        return None
Beispiel #18
0
def get_tool_list(space_type, context_mode):
    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
    return cls._tools[context_mode]
def generate(context, space_type, use_fallback_keys=True, use_reset=True):
    """
    Keymap for popup toolbar, currently generated each time.
    """
    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper

    def modifier_keywords_from_item(kmi):
        kw = {}
        for (attr, default) in (
            ("any", False),
            ("shift", False),
            ("ctrl", False),
            ("alt", False),
            ("oskey", False),
            ("key_modifier", 'NONE'),
        ):
            val = getattr(kmi, attr)
            if val != default:
                kw[attr] = val
        return kw

    def dict_as_tuple(d):
        return tuple((k, v) for (k, v) in sorted(d.items()))

    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)

    items_all = [
        # 0: tool
        # 1: keymap item (direct access)
        # 2: keymap item (newly calculated for toolbar)
        [item, None, None] for item in ToolSelectPanelHelper._tools_flatten(
            cls.tools_from_context(context)) if item is not None
    ]
    items_all_id = {item_container[0].idname for item_container in items_all}

    # Press the toolbar popup key again to set the default tool,
    # this is useful because the select box tool is useful as a way
    # to 'drop' currently active tools (it's basically a 'none' tool).
    # so this allows us to quickly go back to a state that allows
    # a shortcut based workflow (before the tool system was added).
    use_tap_reset = use_reset
    # TODO: support other tools for modes which don't use this tool.
    tap_reset_tool = "builtin.cursor"
    # Check the tool is available in the current context.
    if tap_reset_tool not in items_all_id:
        use_tap_reset = False

    from bl_operators.wm import use_toolbar_release_hack

    # Pie-menu style release to activate.
    use_release_confirm = use_reset

    # Generate items when no keys are mapped.
    use_auto_keymap_alpha = False  # Map manually in the default key-map.
    use_auto_keymap_num = use_fallback_keys

    # Temporary, only create so we can pass 'properties' to find_item_from_operator.
    use_hack_properties = True

    km_name_default = "Toolbar Popup"
    km_name = km_name_default + " <temp>"
    wm = context.window_manager
    keyconf_user = wm.keyconfigs.user
    keyconf_active = wm.keyconfigs.active

    keymap = keyconf_active.keymaps.get(km_name)
    if keymap is None:
        keymap = keyconf_active.keymaps.new(km_name,
                                            space_type='EMPTY',
                                            region_type='TEMPORARY')
    for kmi in keymap.keymap_items:
        keymap.keymap_items.remove(kmi)

    keymap_src = keyconf_user.keymaps.get(km_name_default)
    if keymap_src is not None:
        for kmi_src in keymap_src.keymap_items:
            # Skip tools that aren't currently shown.
            if ((kmi_src.idname == "wm.tool_set_by_id")
                    and (kmi_src.properties.name not in items_all_id)):
                continue
            keymap.keymap_items.new_from_item(kmi_src)
    del keymap_src
    del items_all_id

    kmi_unique_args = set()

    def kmi_unique_or_pass(kmi_args):
        kmi_unique_len = len(kmi_unique_args)
        kmi_unique_args.add(dict_as_tuple(kmi_args))
        return kmi_unique_len != len(kmi_unique_args)

    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)

    if use_hack_properties:
        kmi_hack = keymap.keymap_items.new("wm.tool_set_by_id", 'NONE',
                                           'PRESS')
        kmi_hack_properties = kmi_hack.properties
        kmi_hack.active = False

        kmi_hack_brush_select = keymap.keymap_items.new(
            "paint.brush_select", 'NONE', 'PRESS')
        kmi_hack_brush_select_properties = kmi_hack_brush_select.properties
        kmi_hack_brush_select.active = False

    if use_release_confirm or use_tap_reset:
        kmi_toolbar = wm.keyconfigs.find_item_from_operator(
            idname="wm.toolbar", )[1]
        kmi_toolbar_type = None if not kmi_toolbar else kmi_toolbar.type
        if use_tap_reset and kmi_toolbar_type is not None:
            kmi_toolbar_args_type_only = {"type": kmi_toolbar_type}
            kmi_toolbar_args = {
                **kmi_toolbar_args_type_only,
                **modifier_keywords_from_item(kmi_toolbar)
            }
        else:
            use_tap_reset = False
        del kmi_toolbar

    if use_tap_reset:
        kmi_found = None
        if use_hack_properties:
            # First check for direct assignment, if this tool already has a key, no need to add a new one.
            kmi_hack_properties.name = tap_reset_tool
            kmi_found = wm.keyconfigs.find_item_from_operator(
                idname="wm.tool_set_by_id",
                context='INVOKE_REGION_WIN',
                # properties={"name": item.idname},
                properties=kmi_hack_properties,
                include={'KEYBOARD'},
            )[1]
            if kmi_found:
                use_tap_reset = False
        del kmi_found

    if use_tap_reset:
        use_tap_reset = kmi_unique_or_pass(kmi_toolbar_args)

    if use_tap_reset:
        items_all[:] = [
            item_container for item_container in items_all
            if item_container[0].idname != tap_reset_tool
        ]

    # -----------------------
    # Begin Keymap Generation

    # -------------------------------------------------------------------------
    # Direct Tool Assignment & Brushes

    for item_container in items_all:
        item = item_container[0]
        # Only check the first item in the tools key-map (a little arbitrary).
        if use_hack_properties:
            # First check for direct assignment.
            kmi_hack_properties.name = item.idname
            kmi_found = wm.keyconfigs.find_item_from_operator(
                idname="wm.tool_set_by_id",
                context='INVOKE_REGION_WIN',
                # properties={"name": item.idname},
                properties=kmi_hack_properties,
                include={'KEYBOARD'},
            )[1]

            if kmi_found is None:
                if item.data_block:
                    # PAINT_OT_brush_select
                    mode = context.active_object.mode
                    # See: BKE_paint_get_tool_prop_id_from_paintmode
                    attr = {
                        'SCULPT': "sculpt_tool",
                        'VERTEX_PAINT': "vertex_tool",
                        'WEIGHT_PAINT': "weight_tool",
                        'TEXTURE_PAINT': "image_tool",
                        'PAINT_GPENCIL': "gpencil_tool",
                        'VERTEX_GPENCIL': "gpencil_vertex_tool",
                        'SCULPT_GPENCIL': "gpencil_sculpt_tool",
                        'WEIGHT_GPENCIL': "gpencil_weight_tool",
                    }.get(mode, None)
                    if attr is not None:
                        setattr(kmi_hack_brush_select_properties, attr,
                                item.data_block)
                        kmi_found = wm.keyconfigs.find_item_from_operator(
                            idname="paint.brush_select",
                            context='INVOKE_REGION_WIN',
                            properties=kmi_hack_brush_select_properties,
                            include={'KEYBOARD'},
                        )[1]
                    elif mode in {'PARTICLE_EDIT', 'SCULPT_GPENCIL'}:
                        # Doesn't use brushes
                        pass
                    else:
                        print("Unsupported mode:", mode)
                    del mode, attr

        else:
            kmi_found = None

        if kmi_found is not None:
            pass
        elif item.operator is not None:
            kmi_found = wm.keyconfigs.find_item_from_operator(
                idname=item.operator,
                context='INVOKE_REGION_WIN',
                include={'KEYBOARD'},
            )[1]
        elif item.keymap is not None:
            km = keyconf_user.keymaps.get(item.keymap[0])
            if km is None:
                print("Keymap", repr(item.keymap[0]), "not found for tool",
                      item.idname)
                kmi_found = None
            else:
                kmi_first = km.keymap_items
                kmi_first = kmi_first[0] if kmi_first else None
                if kmi_first is not None:
                    kmi_found = wm.keyconfigs.find_item_from_operator(
                        idname=kmi_first.idname,
                        # properties=kmi_first.properties,  # prevents matches, don't use.
                        context='INVOKE_REGION_WIN',
                        include={'KEYBOARD'},
                    )[1]
                    if kmi_found is None:
                        # We need non-keyboard events so keys with 'key_modifier' key is found.
                        kmi_found = wm.keyconfigs.find_item_from_operator(
                            idname=kmi_first.idname,
                            # properties=kmi_first.properties,  # prevents matches, don't use.
                            context='INVOKE_REGION_WIN',
                            exclude={'KEYBOARD'},
                        )[1]
                        if kmi_found is not None:
                            if kmi_found.key_modifier == 'NONE':
                                kmi_found = None
                else:
                    kmi_found = None
                del kmi_first
            del km
        else:
            kmi_found = None
        item_container[1] = kmi_found

    # -------------------------------------------------------------------------
    # Single Key Access

    # More complex multi-pass test.
    for item_container in items_all:
        item, kmi_found = item_container[:2]
        if kmi_found is None:
            continue
        kmi_found_type = kmi_found.type

        # Only for single keys.
        if ((len(kmi_found_type) == 1) or
                # When a tool is being activated instead of running an operator, just copy the shortcut.
            (kmi_found.idname in {"wm.tool_set_by_id", "WM_OT_tool_set_by_id"}
             )):
            kmi_args = {
                "type": kmi_found_type,
                **modifier_keywords_from_item(kmi_found)
            }
            if kmi_unique_or_pass(kmi_args):
                kmi = keymap.keymap_items.new(idname="wm.tool_set_by_id",
                                              value='PRESS',
                                              **kmi_args)
                kmi.properties.name = item.idname
                item_container[2] = kmi

    # -------------------------------------------------------------------------
    # Single Key Modifier
    #
    #
    # Test for key_modifier, where alpha key is used as a 'key_modifier'
    # (grease pencil holding 'D' for example).

    for item_container in items_all:
        item, kmi_found, kmi_exist = item_container
        if kmi_found is None or kmi_exist:
            continue

        kmi_found_type = kmi_found.type
        if kmi_found_type in {
                'LEFTMOUSE',
                'RIGHTMOUSE',
                'MIDDLEMOUSE',
                'BUTTON4MOUSE',
                'BUTTON5MOUSE',
                'BUTTON6MOUSE',
                'BUTTON7MOUSE',
        }:
            kmi_found_type = kmi_found.key_modifier
            # excludes 'NONE'
            if len(kmi_found_type) == 1:
                kmi_args = {
                    "type": kmi_found_type,
                    **modifier_keywords_from_item(kmi_found)
                }
                del kmi_args["key_modifier"]
                if kmi_unique_or_pass(kmi_args):
                    kmi = keymap.keymap_items.new(idname="wm.tool_set_by_id",
                                                  value='PRESS',
                                                  **kmi_args)
                    kmi.properties.name = item.idname
                    item_container[2] = kmi

    # -------------------------------------------------------------------------
    # Assign A-Z to Keys
    #
    # When the keys are free.

    if use_auto_keymap_alpha:
        # Map all unmapped keys to numbers,
        # while this is a bit strange it means users will not confuse regular key bindings to ordered bindings.

        # First map A-Z.
        kmi_type_alpha_char = [chr(i) for i in range(65, 91)]
        kmi_type_alpha_args = {c: {"type": c} for c in kmi_type_alpha_char}
        kmi_type_alpha_args_tuple = {
            c: dict_as_tuple(kmi_type_alpha_args[c])
            for c in kmi_type_alpha_char
        }
        for item_container in items_all:
            item, kmi_found, kmi_exist = item_container
            if kmi_exist:
                continue
            kmi_type = item.label[0].upper()
            kmi_tuple = kmi_type_alpha_args_tuple.get(kmi_type)
            if kmi_tuple and kmi_tuple not in kmi_unique_args:
                kmi_unique_args.add(kmi_tuple)
                kmi = keymap.keymap_items.new(
                    idname="wm.tool_set_by_id",
                    value='PRESS',
                    **kmi_type_alpha_args[kmi_type],
                )
                kmi.properties.name = item.idname
                item_container[2] = kmi
        del kmi_type_alpha_char, kmi_type_alpha_args, kmi_type_alpha_args_tuple

    # -------------------------------------------------------------------------
    # Assign Numbers to Keys

    if use_auto_keymap_num:
        # Free events (last used first).
        kmi_type_auto = ('ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN',
                         'EIGHT', 'NINE', 'ZERO')
        # Map both numbers and num-pad.
        kmi_type_dupe = {
            'ONE': 'NUMPAD_1',
            'TWO': 'NUMPAD_2',
            'THREE': 'NUMPAD_3',
            'FOUR': 'NUMPAD_4',
            'FIVE': 'NUMPAD_5',
            'SIX': 'NUMPAD_6',
            'SEVEN': 'NUMPAD_7',
            'EIGHT': 'NUMPAD_8',
            'NINE': 'NUMPAD_9',
            'ZERO': 'NUMPAD_0',
        }

        def iter_free_events():
            for mod in ({}, {"shift": True}, {"ctrl": True}, {"alt": True}):
                for e in kmi_type_auto:
                    yield (e, mod)

        iter_events = iter(iter_free_events())

        for item_container in items_all:
            item, kmi_found, kmi_exist = item_container
            if kmi_exist:
                continue
            kmi_args = None
            while True:
                key, mod = next(iter_events, (None, None))
                if key is None:
                    break
                kmi_args = {"type": key, **mod}
                kmi_tuple = dict_as_tuple(kmi_args)
                if kmi_tuple in kmi_unique_args:
                    kmi_args = None
                else:
                    break

            if kmi_args is not None:
                kmi = keymap.keymap_items.new(idname="wm.tool_set_by_id",
                                              value='PRESS',
                                              **kmi_args)
                kmi.properties.name = item.idname
                item_container[2] = kmi
                kmi_unique_args.add(kmi_tuple)

                key = kmi_type_dupe.get(kmi_args["type"])
                if key is not None:
                    kmi_args["type"] = key
                    kmi_tuple = dict_as_tuple(kmi_args)
                    if not kmi_tuple in kmi_unique_args:
                        kmi = keymap.keymap_items.new(
                            idname="wm.tool_set_by_id",
                            value='PRESS',
                            **kmi_args)
                        kmi.properties.name = item.idname
                        kmi_unique_args.add(kmi_tuple)

    # ---------------------
    # End Keymap Generation

    if use_hack_properties:
        keymap.keymap_items.remove(kmi_hack)
        keymap.keymap_items.remove(kmi_hack_brush_select)

    # Keep last so we can try add a key without any modifiers
    # in the case this toolbar was activated with modifiers.
    if use_tap_reset:
        if len(kmi_toolbar_args_type_only) == len(kmi_toolbar_args):
            kmi_toolbar_args_available = kmi_toolbar_args
        else:
            # We have modifiers, see if we have a free key w/o modifiers.
            kmi_toolbar_tuple = dict_as_tuple(kmi_toolbar_args_type_only)
            if kmi_toolbar_tuple not in kmi_unique_args:
                kmi_toolbar_args_available = kmi_toolbar_args_type_only
                kmi_unique_args.add(kmi_toolbar_tuple)
            else:
                kmi_toolbar_args_available = kmi_toolbar_args
            del kmi_toolbar_tuple

        kmi = keymap.keymap_items.new(
            "wm.tool_set_by_id",
            value='PRESS' if use_toolbar_release_hack else 'DOUBLE_CLICK',
            **kmi_toolbar_args_available,
        )
        kmi.properties.name = tap_reset_tool

    if use_release_confirm and (kmi_toolbar_type is not None):
        kmi = keymap.keymap_items.new(
            "ui.button_execute",
            type=kmi_toolbar_type,
            value='RELEASE',
            any=True,
        )
        kmi.properties.skip_depressed = True

        if use_toolbar_release_hack:
            # ... or pass through to let the toolbar know we're released.
            # Let the operator know we're released.
            kmi = keymap.keymap_items.new(
                "wm.tool_set_by_id",
                type=kmi_toolbar_type,
                value='RELEASE',
                any=True,
            )

    wm.keyconfigs.update()
    return keymap
Beispiel #20
0
def unregister_tool(tool_cls):
    space_type = tool_cls.bl_space_type
    context_mode = tool_cls.bl_context_mode

    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
    if cls is None:
        raise Exception("Space type %r has no toolbar" % space_type)
    tools = cls._tools[context_mode]

    tool_def = tool_cls._bl_tool
    try:
        i = tools.index(tool_def)
    except ValueError:
        i = -1

    def tool_list_clean(tool_list):
        # Trim separators.
        while tool_list and tool_list[-1] is None:
            del tool_list[-1]
        while tool_list and tool_list[0] is None:
            del tool_list[0]
        # Remove duplicate separators.
        for i in range(len(tool_list) - 1, -1, -1):
            is_none = tool_list[i] is None
            if is_none and prev_is_none:
                del tool_list[i]
            prev_is_none = is_none

    changed = False
    if i != -1:
        del tools[i]
        tool_list_clean(tools)
        changed = True

    if not changed:
        for i, item in enumerate(tools):
            if isinstance(item, tuple):
                try:
                    j = item.index(tool_def)
                except ValueError:
                    j = -1

                if j != -1:
                    item_clean = list(item)
                    del item_clean[j]
                    tool_list_clean(item_clean)
                    if item_clean:
                        tools[i] = tuple(item_clean)
                    else:
                        del tools[i]
                        tool_list_clean(tools)
                    del item_clean

                    # tuple(sub_item for sub_item in items if sub_item is not tool_def)
                    changed = True
                    break

    if not changed:
        raise Exception("Unable to remove %r" % tool_cls)
    del tool_cls._bl_tool

    keymap_data = tool_def.keymap
    if keymap_data is not None:
        from bpy import context
        wm = context.window_manager
        keyconfigs = wm.keyconfigs
        for kc in (keyconfigs.default, keyconfigs.addon):
            km = kc.keymaps.get(keymap_data[0])
            if km is None:
                print("Warning keymap %r not found in %r!" %
                      (keymap_data[0], kc.name))
            else:
                kc.keymaps.remove(km)
Beispiel #21
0
def register_tool(tool_cls, *, after=None, separator=False, group=False):
    """
    Register a tool in the toolbar.

    :arg tool: A tool subclass.
    :type tool: :class:`bpy.types.WorkSpaceTool` subclass.
    :arg space_type: Space type identifier.
    :type space_type: string
    :arg after: Optional identifiers this tool will be added after.
    :type after: collection of strings or None.
    :arg separator: When true, add a separator before this tool.
    :type separator: bool
    :arg group: When true, add a new nested group of tools.
    :type group: bool
    """
    space_type = tool_cls.bl_space_type
    context_mode = tool_cls.bl_context_mode

    from bl_ui.space_toolsystem_common import (
        ToolSelectPanelHelper,
        ToolDef,
    )

    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
    if cls is None:
        raise Exception("Space type %r has no toolbar" % space_type)
    tools = cls._tools[context_mode]

    # First sanity check
    from bpy.types import WorkSpaceTool
    tools_id = {
        item.idname
        for item in ToolSelectPanelHelper._tools_flatten(tools)
        if item is not None
    }
    if not issubclass(tool_cls, WorkSpaceTool):
        raise Exception("Expected WorkSpaceTool subclass, not %r" %
                        type(tool_cls))
    if tool_cls.bl_idname in tools_id:
        raise Exception("Tool %r already exists!" % tool_cls.bl_idname)
    del tools_id, WorkSpaceTool

    # Convert the class into a ToolDef.
    def tool_from_class(tool_cls):
        # Convert class to tuple, store in the class for removal.
        tool_def = ToolDef.from_dict({
            "idname":
            tool_cls.bl_idname,
            "label":
            tool_cls.bl_label,
            "description":
            getattr(tool_cls, "bl_description", tool_cls.__doc__),
            "icon":
            getattr(tool_cls, "bl_icon", None),
            "cursor":
            getattr(tool_cls, "bl_cursor", None),
            "options":
            getattr(tool_cls, "bl_options", None),
            "widget":
            getattr(tool_cls, "bl_widget", None),
            "widget_properties":
            getattr(tool_cls, "bl_widget_properties", None),
            "keymap":
            getattr(tool_cls, "bl_keymap", None),
            "data_block":
            getattr(tool_cls, "bl_data_block", None),
            "operator":
            getattr(tool_cls, "bl_operator", None),
            "draw_settings":
            getattr(tool_cls, "draw_settings", None),
            "draw_cursor":
            getattr(tool_cls, "draw_cursor", None),
        })
        tool_cls._bl_tool = tool_def

        keymap_data = tool_def.keymap
        if keymap_data is not None:
            if context_mode is None:
                context_descr = "All"
            else:
                context_descr = context_mode.replace("_", " ").title()
            from bpy import context
            wm = context.window_manager
            keyconfigs = wm.keyconfigs
            kc_default = keyconfigs.default
            # Note that Blender's default tools use the default key-config for both.
            # We need to use the add-ons for 3rd party tools so reloading the key-map doesn't clear them.
            kc = keyconfigs.addon
            if callable(keymap_data[0]):
                cls._km_action_simple(kc_default, kc, context_descr,
                                      tool_def.label, keymap_data)
        return tool_def

    tool_converted = tool_from_class(tool_cls)

    if group:
        # Create a new group
        tool_converted = (tool_converted, )

    tool_def_insert = ((None, tool_converted) if separator else
                       (tool_converted, ))

    def skip_to_end_of_group(seq, i):
        i_prev = i
        while i < len(seq) and seq[i] is not None:
            i_prev = i
            i += 1
        return i_prev

    changed = False
    if after is not None:
        for i, item in enumerate(tools):
            if item is None:
                pass
            elif isinstance(item, ToolDef):
                if item.idname in after:
                    i = skip_to_end_of_group(item, i)
                    tools[i + 1:i + 1] = tool_def_insert
                    changed = True
                    break
            elif isinstance(item, tuple):
                for j, sub_item in enumerate(item, 1):
                    if isinstance(sub_item, ToolDef):
                        if sub_item.idname in after:
                            if group:
                                # Can't add a group within a group,
                                # add a new group after this group.
                                i = skip_to_end_of_group(tools, i)
                                tools[i + 1:i + 1] = tool_def_insert
                            else:
                                j = skip_to_end_of_group(item, j)
                                item = item[:j +
                                            1] + tool_def_insert + item[j + 1:]
                                tools[i] = item
                            changed = True
                            break
                if changed:
                    break

        if not changed:
            print("bpy.utils.register_tool: could not find 'after'", after)
    if not changed:
        tools.extend(tool_def_insert)
 def _fn():
     from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
     for cls in ToolSelectPanelHelper.__subclasses__():
         if cls.bl_space_type == space_type:
             return cls.keymap_ui_hierarchy(context_mode)
     raise Exception("keymap not found")
Beispiel #23
0
def unregister_tool_legacy(tool_cls):
    # fix https://developer.blender.org/T60766
    space_type = tool_cls.bl_space_type
    context_mode = tool_cls.bl_context_mode

    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
    if cls is None:
        raise Exception(f"Space type {space_type!r} has no toolbar")
    tools = cls._tools[context_mode]

    tool_def = tool_cls._bl_tool
    try:
        i = tools.index(tool_def)
    except ValueError:
        i = -1

    def tool_list_clean(tool_list):
        # Trim separators.
        while tool_list and tool_list[-1] is None:
            del tool_list[-1]
        while tool_list and tool_list[0] is None:
            del tool_list[0]
        is_none_prev = False
        # Remove duplicate separators.
        for i in range(len(tool_list) - 1, -1, -1):
            is_none = tool_list[i] is None
            if is_none and prev_is_none:
                del tool_list[i]
            prev_is_none = is_none

    changed = False
    if i != -1:
        del tools[i]
        tool_list_clean(tools)
        changed = True

    if not changed:
        for i, item in enumerate(tools):
            if isinstance(item, tuple):
                try:
                    j = item.index(tool_def)
                except ValueError:
                    j = -1

                if j != -1:
                    item_clean = list(item)
                    del item_clean[j]
                    tool_list_clean(item_clean)
                    if item_clean:
                        tools[i] = tuple(item_clean)
                    else:
                        del tools[i]
                        tool_list_clean(tools)
                    del item_clean

                    # tuple(sub_item for sub_item in items if sub_item is not tool_def)
                    changed = True
                    break

    if not changed:
        raise Exception(f"Unable to remove {tool_cls!r}")
    del tool_cls._bl_tool

    keymap_data = tool_def.keymap
    if keymap_data is not None:
        from bpy import context
        wm = context.window_manager
        kc = wm.keyconfigs.user
        km = kc.keymaps.get(keymap_data[0])
        if km is None:
            print("Warning keymap {keymap_data[0]!r} not found!")
        else:
            kc.keymaps.remove(km)
Beispiel #24
0
def register_tool(tool_cls, *, after=None, separator=False, group=False):
    """
    Register a tool in the toolbar.

    :arg tool: A tool subclass.
    :type tool: :class:`bpy.types.WorkSpaceTool` subclass.
    :arg space_type: Space type identifier.
    :type space_type: string
    :arg after: Optional identifiers this tool will be added after.
    :type after: collection of strings or None.
    :arg separator: When true, add a separator before this tool.
    :type separator: bool
    :arg group: When true, add a new nested group of tools.
    :type group: bool
    """
    space_type = tool_cls.bl_space_type
    context_mode = tool_cls.bl_context_mode

    from bl_ui.space_toolsystem_common import (
        ToolSelectPanelHelper,
        ToolDef,
    )

    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
    if cls is None:
        raise Exception(f"Space type {space_type!r} has no toolbar")
    tools = cls._tools[context_mode]

    # First sanity check
    from bpy.types import WorkSpaceTool
    tools_id = {
        item.idname for item in ToolSelectPanelHelper._tools_flatten(tools)
        if item is not None
    }
    if not issubclass(tool_cls, WorkSpaceTool):
        raise Exception(f"Expected WorkSpaceTool subclass, not {type(tool_cls)!r}")
    if tool_cls.bl_idname in tools_id:
        raise Exception(f"Tool {tool_cls.bl_idname!r} already exists!")
    del tools_id, WorkSpaceTool

    # Convert the class into a ToolDef.
    def tool_from_class(tool_cls):
        # Convert class to tuple, store in the class for removal.
        tool_def = ToolDef.from_dict({
            "idname": tool_cls.bl_idname,
            "label": tool_cls.bl_label,
            "description": getattr(tool_cls, "bl_description", tool_cls.__doc__),
            "icon": getattr(tool_cls, "bl_icon", None),
            "cursor": getattr(tool_cls, "bl_cursor", None),
            "widget": getattr(tool_cls, "bl_widget", None),
            "keymap": getattr(tool_cls, "bl_keymap", None),
            "data_block": getattr(tool_cls, "bl_data_block", None),
            "operator": getattr(tool_cls, "bl_operator", None),
            "draw_settings": getattr(tool_cls, "draw_settings", None),
            "draw_cursor": getattr(tool_cls, "draw_cursor", None),
        })
        tool_cls._bl_tool = tool_def

        keymap_data = tool_def.keymap
        if keymap_data is not None:
            if context_mode is None:
                context_descr = "All"
            else:
                context_descr = context_mode.replace("_", " ").title()
            from bpy import context
            wm = context.window_manager
            kc = wm.keyconfigs.default
            if callable(keymap_data[0]):
                cls._km_action_simple(kc, context_descr, tool_def.label, keymap_data)
        return tool_def

    tool_converted = tool_from_class(tool_cls)

    if group:
        # Create a new group
        tool_converted = (tool_converted,)


    tool_def_insert = (
        (None, tool_converted) if separator else
        (tool_converted,)
    )

    def skip_to_end_of_group(seq, i):
        i_prev = i
        while i < len(seq) and seq[i] is not None:
            i_prev = i
            i += 1
        return i_prev

    changed = False
    if after is not None:
        for i, item in enumerate(tools):
            if item is None:
                pass
            elif isinstance(item, ToolDef):
                if item.idname in after:
                    i = skip_to_end_of_group(item, i)
                    tools[i + 1:i + 1] = tool_def_insert
                    changed = True
                    break
            elif isinstance(item, tuple):
                for j, sub_item in enumerate(item, 1):
                    if isinstance(sub_item, ToolDef):
                        if sub_item.idname in after:
                            if group:
                                # Can't add a group within a group,
                                # add a new group after this group.
                                i = skip_to_end_of_group(tools, i)
                                tools[i + 1:i + 1] = tool_def_insert
                            else:
                                j = skip_to_end_of_group(item, j)
                                item = item[:j + 1] + tool_def_insert + item[j + 1:]
                                tools[i] = item
                            changed = True
                            break
                if changed:
                    break

        if not changed:
            print("bpy.utils.register_tool: could not find 'after'", after)
    if not changed:
        tools.extend(tool_def_insert)
Beispiel #25
0
def get_tools_from_space_and_mode(space_type, context_mode):
    return ToolSelectPanelHelper._tool_class_from_space_type(
        space_type)._tools[context_mode]
Beispiel #26
0
 def _fn():
     from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
     for cls in ToolSelectPanelHelper.__subclasses__():
         if cls.bl_space_type == space_type:
             return cls.keymap_ui_hierarchy(context_mode)
     raise Exception("keymap not found")
Beispiel #27
0
def unregister_tool(tool_cls):
    space_type = tool_cls.bl_space_type
    context_mode = tool_cls.bl_context_mode

    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)
    if cls is None:
        raise Exception(f"Space type {space_type!r} has no toolbar")
    tools = cls._tools[context_mode]

    tool_def = tool_cls._bl_tool
    try:
        i = tools.index(tool_def)
    except ValueError:
        i = -1

    def tool_list_clean(tool_list):
        # Trim separators.
        while tool_list and tool_list[-1] is None:
            del tool_list[-1]
        while tool_list and tool_list[0] is None:
            del tool_list[0]
        # Remove duplicate separators.
        for i in range(len(tool_list) - 1, -1, -1):
            is_none = tool_list[i] is None
            if is_none and prev_is_none:
                del tool_list[i]
            prev_is_none = is_none

    changed = False
    if i != -1:
        del tools[i]
        tool_list_clean(tools)
        changed = True

    if not changed:
        for i, item in enumerate(tools):
            if isinstance(item, tuple):
                try:
                    j = item.index(tool_def)
                except ValueError:
                    j = -1

                if j != -1:
                    item_clean = list(item)
                    del item_clean[j]
                    tool_list_clean(item_clean)
                    if item_clean:
                        tools[i] = tuple(item_clean)
                    else:
                        del tools[i]
                        tool_list_clean(tools)
                    del item_clean

                    # tuple(sub_item for sub_item in items if sub_item is not tool_def)
                    changed = True
                    break

    if not changed:
        raise Exception(f"Unable to remove {tool_cls!r}")
    del tool_cls._bl_tool

    keymap_data = tool_def.keymap
    if keymap_data is not None:
        from bpy import context
        wm = context.window_manager
        kc = wm.keyconfigs.default
        km = kc.keymaps.get(keymap_data[0])
        if km is None:
            print("Warning keymap {keymap_data[0]!r} not found!")
        else:
            kc.keymaps.remove(km)
Beispiel #28
0
def generate(context, space_type):
    """
    Keymap for popup toolbar, currently generated each time.
    """
    from bl_ui.space_toolsystem_common import ToolSelectPanelHelper

    def modifier_keywords_from_item(kmi):
        kw = {}
        for (attr, default) in (
            ("any", False),
            ("shift", False),
            ("ctrl", False),
            ("alt", False),
            ("oskey", False),
            ("key_modifier", 'NONE'),
        ):
            val = getattr(kmi, attr)
            if val != default:
                kw[attr] = val
        return kw

    def dict_as_tuple(d):
        return tuple((k, v) for (k, v) in sorted(d.items()))

    tool_blacklist = set()

    use_simple_keymap = False

    # Press the toolbar popup key again to set the default tool,
    # this is useful because the select box tool is useful as a way
    # to 'drop' currently active tools (it's basically a 'none' tool).
    # so this allows us to quickly go back to a state that allows
    # a shortcut based workflow (before the tool system was added).
    use_tap_reset = True
    # TODO: support other tools for modes which don't use this tool.
    tap_reset_tool = "Cursor"
    # Check the tool is available in the current context.
    if ToolSelectPanelHelper._tool_get_by_name(context, space_type,
                                               tap_reset_tool)[1] is None:
        use_tap_reset = False

    from bl_operators.wm import use_toolbar_release_hack

    # Pie-menu style release to activate.
    use_release_confirm = True

    # Generate items when no keys are mapped.
    use_auto_keymap = True

    # Temporary, only create so we can pass 'properties' to find_item_from_operator.
    use_hack_properties = True

    km_name = "Toolbar Popup"
    wm = context.window_manager
    keyconf = wm.keyconfigs.active
    keymap = keyconf.keymaps.get(km_name)
    if keymap is None:
        keymap = keyconf.keymaps.new(km_name,
                                     space_type='EMPTY',
                                     region_type='TEMPORARY',
                                     tool=True)
    for kmi in keymap.keymap_items:
        keymap.keymap_items.remove(kmi)

    kmi_unique_args = set()

    cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type)

    if use_hack_properties:
        kmi_hack = keymap.keymap_items.new("wm.tool_set_by_name", 'A', 'PRESS')
        kmi_hack_properties = kmi_hack.properties

        kmi_hack_brush_select = keymap.keymap_items.new(
            "paint.brush_select", 'A', 'PRESS')
        kmi_hack_brush_select_properties = kmi_hack_brush_select.properties

    if use_release_confirm or use_tap_reset:
        kmi_toolbar = wm.keyconfigs.find_item_from_operator(
            idname="wm.toolbar")[1]
        kmi_toolbar_type = None if not kmi_toolbar else kmi_toolbar.type
        if use_tap_reset and kmi_toolbar_type is not None:
            kmi_toolbar_args_type_only = {"type": kmi_toolbar_type}
            kmi_toolbar_args = {
                **kmi_toolbar_args_type_only,
                **modifier_keywords_from_item(kmi_toolbar)
            }
        else:
            use_tap_reset = False
        del kmi_toolbar

    if use_tap_reset:
        kmi_found = None
        if use_hack_properties:
            # First check for direct assignment, if this tool already has a key, no need to add a new one.
            kmi_hack_properties.name = tap_reset_tool
            kmi_found = wm.keyconfigs.find_item_from_operator(
                idname="wm.tool_set_by_name",
                context='INVOKE_REGION_WIN',
                # properties={"name": item.text},
                properties=kmi_hack_properties,
            )[1]
            if kmi_found:
                use_tap_reset = False
        del kmi_found

    if use_tap_reset:
        kmi_toolbar_tuple = dict_as_tuple(kmi_toolbar_args)
        if kmi_toolbar_tuple not in kmi_unique_args:
            # Used after keymap is setup.
            kmi_unique_args.add(kmi_toolbar_tuple)
        else:
            use_tap_reset = False
        del kmi_toolbar_tuple

    if use_tap_reset:
        tool_blacklist.add(tap_reset_tool)

    items_all = [
        # 0: tool
        # 1: keymap item (direct access)
        # 2: keymap item (newly calculated for toolbar)
        [item, None, None] for item in ToolSelectPanelHelper._tools_flatten(
            cls.tools_from_context(context)) if item is not None
        if item.text not in tool_blacklist
    ]

    if use_simple_keymap:
        # Simply assign a key from A-Z.
        for i, (item, _, _) in enumerate(items_all):
            key = chr(ord('A') + i)
            kmi = keymap.keymap_items.new("wm.tool_set_by_name", key, 'PRESS')
            kmi.properties.name = item.text
    else:
        for item_container in items_all:
            item = item_container[0]
            # Only check the first item in the tools key-map (a little arbitrary).
            if use_hack_properties:
                # First check for direct assignment.
                kmi_hack_properties.name = item.text
                kmi_found = wm.keyconfigs.find_item_from_operator(
                    idname="wm.tool_set_by_name",
                    context='INVOKE_REGION_WIN',
                    # properties={"name": item.text},
                    properties=kmi_hack_properties,
                )[1]

                if kmi_found is None:
                    if item.data_block:
                        # PAINT_OT_brush_select
                        mode = context.active_object.mode
                        # See: BKE_paint_get_tool_prop_id_from_paintmode
                        attr = {
                            'SCULPT': "sculpt_tool",
                            'VERTEX_PAINT': "vertex_tool",
                            'WEIGHT_PAINT': "weight_tool",
                            'TEXTURE_PAINT': "image_tool",
                            'GPENCIL_PAINT': "gpencil_tool",
                        }.get(mode, None)
                        if attr is not None:
                            setattr(kmi_hack_brush_select_properties, attr,
                                    item.data_block)
                            kmi_found = wm.keyconfigs.find_item_from_operator(
                                idname="paint.brush_select",
                                context='INVOKE_REGION_WIN',
                                properties=kmi_hack_brush_select_properties,
                            )[1]
                        else:
                            print("Unsupported mode:", mode)
                        del mode, attr

            else:
                kmi_found = None

            if kmi_found is not None:
                pass
            elif item.operator is not None:
                kmi_found = wm.keyconfigs.find_item_from_operator(
                    idname=item.operator,
                    context='INVOKE_REGION_WIN',
                )[1]
            elif item.keymap is not None:
                kmi_first = item.keymap[0].keymap_items
                kmi_first = kmi_first[0] if kmi_first else None
                if kmi_first is not None:
                    kmi_found = wm.keyconfigs.find_item_from_operator(
                        idname=kmi_first.idname,
                        # properties=kmi_first.properties,  # prevents matches, don't use.
                        context='INVOKE_REGION_WIN',
                    )[1]
                else:
                    kmi_found = None
                del kmi_first
            else:
                kmi_found = None
            item_container[1] = kmi_found

        # More complex multi-pass test.
        for item_container in items_all:
            item, kmi_found = item_container[:2]
            if kmi_found is None:
                continue
            kmi_found_type = kmi_found.type

            # Only for single keys.
            if ((len(kmi_found_type) == 1) or
                    # When a tool is being activated instead of running an operator, just copy the shortcut.
                (kmi_found.idname
                 in {"wm.tool_set_by_name", "WM_OT_tool_set_by_name"})):
                kmi_args = {
                    "type": kmi_found_type,
                    **modifier_keywords_from_item(kmi_found)
                }
                kmi = keymap.keymap_items.new(idname="wm.tool_set_by_name",
                                              value='PRESS',
                                              **kmi_args)
                kmi.properties.name = item.text
                item_container[2] = kmi
                if use_auto_keymap:
                    kmi_unique_args.add(dict_as_tuple(kmi_args))

        # Test for key_modifier, where alpha key is used as a 'key_modifier'
        # (grease pencil holding 'D' for example).
        for item_container in items_all:
            item, kmi_found, kmi_exist = item_container
            if kmi_found is None or kmi_exist:
                continue

            kmi_found_type = kmi_found.type
            if kmi_found_type in {
                    'LEFTMOUSE',
                    'RIGHTMOUSE',
                    'MIDDLEMOUSE',
                    'BUTTON4MOUSE',
                    'BUTTON5MOUSE',
                    'BUTTON6MOUSE',
                    'BUTTON7MOUSE',
            }:
                kmi_found_type = kmi_found.key_modifier
                # excludes 'NONE'
                if len(kmi_found_type) == 1:
                    kmi_args = {
                        "type": kmi_found_type,
                        **modifier_keywords_from_item(kmi_found)
                    }
                    del kmi_args["key_modifier"]
                    kmi_tuple = dict_as_tuple(kmi_args)
                    if kmi_tuple in kmi_unique_args:
                        continue
                    kmi = keymap.keymap_items.new(idname="wm.tool_set_by_name",
                                                  value='PRESS',
                                                  **kmi_args)
                    kmi.properties.name = item.text
                    item_container[2] = kmi
                    if use_auto_keymap:
                        kmi_unique_args.add(kmi_tuple)

        if use_auto_keymap:
            # Map all unmapped keys to numbers,
            # while this is a bit strange it means users will not confuse regular key bindings to ordered bindings.

            # Free events (last used first).
            kmi_type_auto = ('ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX',
                             'SEVEN', 'EIGHT', 'NINE', 'ZERO')
            # Map both numbers and num-pad.
            kmi_type_dupe = {
                'ONE': 'NUMPAD_1',
                'TWO': 'NUMPAD_2',
                'THREE': 'NUMPAD_3',
                'FOUR': 'NUMPAD_4',
                'FIVE': 'NUMPAD_5',
                'SIX': 'NUMPAD_6',
                'SEVEN': 'NUMPAD_7',
                'EIGHT': 'NUMPAD_8',
                'NINE': 'NUMPAD_9',
                'ZERO': 'NUMPAD_0',
            }

            def iter_free_events():
                for mod in ({}, {
                        "shift": True
                }, {
                        "ctrl": True
                }, {
                        "alt": True
                }):
                    for e in kmi_type_auto:
                        yield (e, mod)

            iter_events = iter(iter_free_events())

            for item_container in items_all:
                item, kmi_found, kmi_exist = item_container
                if kmi_exist:
                    continue
                kmi_args = None
                while True:
                    key, mod = next(iter_events, (None, None))
                    if key is None:
                        break
                    kmi_args = {"type": key, **mod}
                    kmi_tuple = dict_as_tuple(kmi_args)
                    if kmi_tuple in kmi_unique_args:
                        kmi_args = None
                    else:
                        break

                if kmi_args is not None:
                    kmi = keymap.keymap_items.new(idname="wm.tool_set_by_name",
                                                  value='PRESS',
                                                  **kmi_args)
                    kmi.properties.name = item.text
                    item_container[2] = kmi
                    if use_auto_keymap:
                        kmi_unique_args.add(kmi_tuple)

                    key = kmi_type_dupe.get(kmi_args["type"])
                    if key is not None:
                        kmi_args["type"] = key
                        kmi_tuple = dict_as_tuple(kmi_args)
                        if not kmi_tuple in kmi_unique_args:
                            kmi = keymap.keymap_items.new(
                                idname="wm.tool_set_by_name",
                                value='PRESS',
                                **kmi_args)
                            kmi.properties.name = item.text
                            if use_auto_keymap:
                                kmi_unique_args.add(kmi_tuple)

    if use_hack_properties:
        keymap.keymap_items.remove(kmi_hack)

    # Keepo last so we can try add a key without any modifiers
    # in the case this toolbar was activated with modifiers.
    if use_tap_reset:
        if len(kmi_toolbar_args_type_only) == len(kmi_toolbar_args):
            kmi_toolbar_args_available = kmi_toolbar_args
        else:
            # We have modifiers, see if we have a free key w/o modifiers.
            kmi_toolbar_tuple = dict_as_tuple(kmi_toolbar_args_type_only)
            if kmi_toolbar_tuple not in kmi_unique_args:
                kmi_toolbar_args_available = kmi_toolbar_args_type_only
                kmi_unique_args.add(kmi_toolbar_tuple)
            else:
                kmi_toolbar_args_available = kmi_toolbar_args
            del kmi_toolbar_tuple

        kmi = keymap.keymap_items.new(
            "wm.tool_set_by_name",
            value='PRESS' if use_toolbar_release_hack else 'DOUBLE_CLICK',
            **kmi_toolbar_args_available,
        )
        kmi.properties.name = tap_reset_tool

    if use_release_confirm:
        kmi = keymap.keymap_items.new(
            "ui.button_execute",
            type=kmi_toolbar_type,
            value='RELEASE',
            any=True,
        )
        kmi.properties.skip_depressed = True

        if use_toolbar_release_hack:
            # ... or pass through to let the toolbar know we're released.
            # Let the operator know we're released.
            kmi = keymap.keymap_items.new(
                "wm.tool_set_by_name",
                type=kmi_toolbar_type,
                value='RELEASE',
                any=True,
            )

    wm.keyconfigs.update()
    return keymap