В Blender, начиная с версии 2.8x, появилась новая панель инструментов, расположенная в рабочей области 3D вьюпорта с левой стороны. Создавать пользовательские инструменты и добавлять их в эту панель можно при помощи Blender Python API.
Для того чтобы создать пользовательский инструмент, его, точно так же как и пользовательские операторы, нужно описать в отдельном классе.
Для инструментов класс должен быть наследован от базового класса bpy.types.WorkSpaceTool.
Далее, так же как и для операторов, нужно определить обязательные параметры инструмента:
bl_space_type – рабочую область, в которой будет использоваться инструмент. Например, “VIEW_3D” для 3D вьюпорта.
bl_context_mode – контекст инструмента, например “EDIT”, если инструмент используется в режиме редактирования объекта.
bl_idname – идентификатор для данного инструмента.
bl_label – краткое описание инструмента. Появляется при наведении на иконку курсора мышки.
bl_description – полное описание инструмента. Появляется при задержке курсора над иконкой инструмента. Может быть многострочным, если задано в формате кортежа.
bl_icon – указатель на иконку для инструмента, которая будет отображаться в панели инструментов. Все иконки, доступные для инструментов, лежат в отдельных файлах в директории
1 |
путь_к_директории_Blender/версия_Blender/datafiles/icons/ |
Названия файлов соответствуют идентификатору иконки, который нужно указать в параметре bl_icon.
И, самое основное – параметр bl_keymap – действия, которые инструмент будет выполнять.
В этом параметре в виде кортежа описывается список возможных действий инструмента. Каждый элемент – одно действие.
Каждое действие описывается отдельным кортежом.
Первый элемент такого кортежа – идентификатор оператора, без префикса bpy.ops. Именно этот оператор будет выполнен при использовании инструмента. Например, для выбора объекта во вьюпорте указывается значение “view3d.select”.
Второй элемент кортежа – словарь с параметрами вызова инструмента. Здесь описываются действия пользователя. Например, клик левой кнопкой мышки описывается следующим образом:
1 2 3 4 |
{ 'type': 'LEFTMOUSE', 'value': 'CLICK' } |
Третий элемент кортежа представляет собой еще один словарь, в котором указываются параметры, передаваемые в оператор. Например, для того, чтобы снять выделение со всех объектов, в оператор view3d.select нужно передать параметр “deselect_all” со значением True. В нашем случае указание параметра будет задаваться следующим образом:
1 2 3 4 5 |
{ 'properties': [ ('deselect_all', True) ] } |
Пример класса для создания пользовательского инструмента, эмулирующего выделение объектов кликами и рамкой:
Автор кода Andrej.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class TestTool(bpy.types.WorkSpaceTool): bl_space_type = 'VIEW_3D' bl_context_mode = 'OBJECT' bl_idname = 'test_tool.test_tool_select' bl_label = 'Test Select' bl_description = ( 'This is a tooltip\n' 'with multiple lines' ) bl_icon = 'ops.generic.select_circle' bl_keymap = ( ('view3d.select_box', {'type': 'LEFTMOUSE', 'value': 'CLICK_DRAG'}, None), ('view3d.select_box', {'type': 'LEFTMOUSE', 'value': 'CLICK_DRAG', 'shift': True}, {'properties': [('mode', 'ADD')]}), ('view3d.select_box', {'type': 'LEFTMOUSE', 'value': 'CLICK_DRAG', 'ctrl': True}, {'properties': [('mode', 'SUB')]}), ('view3d.select_box', {'type': 'LEFTMOUSE', 'value': 'CLICK_DRAG', 'shift': True, 'ctrl': True}, {'properties': [('mode', 'AND')]}), ('view3d.select', {'type': 'LEFTMOUSE', 'value': 'CLICK'}, {'properties': [('deselect_all', True)]}), ('view3d.select', {'type': 'LEFTMOUSE', 'value': 'CLICK', 'shift': True}, {'properties': [('toggle', True)]}), ('view3d.select', {'type': 'LEFTMOUSE', 'value': 'CLICK', 'alt': True}, {'properties': [('enumerate', True)]}), ('view3d.select', {'type': 'LEFTMOUSE', 'value': 'CLICK', 'shift': True, 'alt': True}, {'properties': [('toggle', True), ('enumerate', True)]}) ) |
Для того чтобы подключить данный инструмент в панель инструментов 3D вьюпорта нужно зарегистрировать класс в Blender Python API:
1 |
bpy.utils.register_tool(TestTool, after={'builtin.scale_cage'}, separator=True, group=True) |
Если код выполняется из текстового редактора Blender нужно обновить окно вьюпорта, переведя на него курсор мышки, или вызвав обновление при помощи кода:
1 2 |
for area in bpy.context.screen.areas: area.tag_redraw() |