| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  | # ##### BEGIN GPL LICENSE BLOCK ##### | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  | #  modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  | #  as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  | #  of the License, or (at your option) any later version. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | #  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | #  GNU General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | #  along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  | #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # ##### END GPL LICENSE BLOCK ##### | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # <pep8 compliant> | 
					
						
							|  |  |  | import bpy | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  | from bpy.types import ( | 
					
						
							|  |  |  |     Menu, | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | __all__ = ( | 
					
						
							|  |  |  |     "ToolSelectPanelHelper", | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  |     "ToolDef", | 
					
						
							| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-26 15:18:47 +02:00
										 |  |  | # Support reloading icons. | 
					
						
							|  |  |  | if "_icon_cache" in locals(): | 
					
						
							|  |  |  |     release = bpy.app.icons.release | 
					
						
							|  |  |  |     for icon_value in _icon_cache.values(): | 
					
						
							| 
									
										
										
										
											2018-04-30 13:55:15 +02:00
										 |  |  |         if icon_value != 0: | 
					
						
							|  |  |  |             release(icon_value) | 
					
						
							| 
									
										
										
										
											2018-04-26 15:18:47 +02:00
										 |  |  |     del release | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-24 09:19:28 +02:00
										 |  |  | # (filename -> icon_value) map | 
					
						
							|  |  |  | _icon_cache = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  | def _keymap_fn_from_seq(keymap_data): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # standalone | 
					
						
							|  |  |  |     def _props_assign_recursive(rna_props, py_props): | 
					
						
							|  |  |  |         for prop_id, value in py_props.items(): | 
					
						
							|  |  |  |             if isinstance(value, dict): | 
					
						
							|  |  |  |                 _props_assign_recursive(getattr(rna_props, prop_id), value) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 setattr(rna_props, prop_id, value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def keymap_fn(km): | 
					
						
							|  |  |  |         for op_idname, op_props_dict, kmi_kwargs in keymap_fn.keymap_data: | 
					
						
							|  |  |  |             kmi = km.keymap_items.new(op_idname, **kmi_kwargs) | 
					
						
							|  |  |  |             kmi_props = kmi.properties | 
					
						
							|  |  |  |             if op_props_dict: | 
					
						
							|  |  |  |                 _props_assign_recursive(kmi.properties, op_props_dict) | 
					
						
							|  |  |  |     keymap_fn.keymap_data = keymap_data | 
					
						
							|  |  |  |     return keymap_fn | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-29 12:26:00 +02:00
										 |  |  | def _item_is_fn(item): | 
					
						
							| 
									
										
										
										
											2018-04-30 12:14:46 +02:00
										 |  |  |     return (not (type(item) is ToolDef) and callable(item)) | 
					
						
							| 
									
										
										
										
											2018-04-29 12:26:00 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 12:14:46 +02:00
										 |  |  | from collections import namedtuple | 
					
						
							|  |  |  | ToolDef = namedtuple( | 
					
						
							|  |  |  |     "ToolDef", | 
					
						
							|  |  |  |     ( | 
					
						
							|  |  |  |         # The name to display in the interface. | 
					
						
							|  |  |  |         "text", | 
					
						
							|  |  |  |         # The name of the icon to use (found in ``release/datafiles/icons``) or None for no icon. | 
					
						
							|  |  |  |         "icon", | 
					
						
							| 
									
										
										
										
											2018-05-18 07:58:37 +02:00
										 |  |  |         # An optional cursor to use when this tool is active. | 
					
						
							|  |  |  |         "cursor", | 
					
						
							| 
									
										
										
										
											2018-04-30 12:14:46 +02:00
										 |  |  |         # An optional manipulator group to activate when the tool is set or None for no widget. | 
					
						
							|  |  |  |         "widget", | 
					
						
							|  |  |  |         # Optional keymap for tool, either: | 
					
						
							|  |  |  |         # - A function that populates a keymaps passed in as an argument. | 
					
						
							|  |  |  |         # - A tuple filled with triple's of: | 
					
						
							|  |  |  |         #   ``(operator_id, operator_properties, keymap_item_args)``. | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # Warning: currently 'from_dict' this is a list of one item, | 
					
						
							|  |  |  |         # so internally we can swap the keymap function for the keymap it's self. | 
					
						
							|  |  |  |         # This isn't very nice and may change, tool definitions shouldn't care about this. | 
					
						
							|  |  |  |         "keymap", | 
					
						
							|  |  |  |         # Optional data-block assosiated with this tool. | 
					
						
							|  |  |  |         # (Typically brush name, usage depends on mode, we could use for non-brush ID's in other modes). | 
					
						
							|  |  |  |         "data_block", | 
					
						
							|  |  |  |         # Optional draw settings (operator options, toolsettings). | 
					
						
							|  |  |  |         "draw_settings", | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | del namedtuple | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 12:14:46 +02:00
										 |  |  | def from_dict(kw_args): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Use so each tool can avoid defining all members of the named tuple. | 
					
						
							|  |  |  |     Also convert the keymap from a tuple into a function | 
					
						
							|  |  |  |     (since keymap is a callback). | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     kw = { | 
					
						
							|  |  |  |         "icon": None, | 
					
						
							| 
									
										
										
										
											2018-05-18 07:58:37 +02:00
										 |  |  |         "cursor": None, | 
					
						
							| 
									
										
										
										
											2018-04-30 12:14:46 +02:00
										 |  |  |         "widget": None, | 
					
						
							|  |  |  |         "keymap": None, | 
					
						
							|  |  |  |         "data_block": None, | 
					
						
							|  |  |  |         "draw_settings": None, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     kw.update(kw_args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     keymap = kw["keymap"] | 
					
						
							|  |  |  |     if kw["keymap"] is None: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     elif type(keymap) is tuple: | 
					
						
							|  |  |  |         keymap = [_keymap_fn_from_seq(keymap)] | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         keymap = [keymap] | 
					
						
							|  |  |  |     kw["keymap"] = keymap | 
					
						
							|  |  |  |     return ToolDef(**kw) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 12:14:46 +02:00
										 |  |  | def from_fn(fn): | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2018-04-30 12:14:46 +02:00
										 |  |  |     Use as decorator so we can define functions. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     return ToolDef.from_dict(fn()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ToolDef.from_dict = from_dict | 
					
						
							|  |  |  | ToolDef.from_fn = from_fn | 
					
						
							|  |  |  | del from_dict | 
					
						
							|  |  |  | del from_fn | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  | class ToolSelectPanelHelper: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Generic Class, can be used for any toolbar. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     - keymap_prefix: | 
					
						
							|  |  |  |       The text prefix for each key-map for this spaces tools. | 
					
						
							|  |  |  |     - tools_all(): | 
					
						
							| 
									
										
										
										
											2018-04-26 14:43:32 +02:00
										 |  |  |       Returns (context_mode, tools) tuple pair for all tools defined. | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |     - tools_from_context(context, mode=None): | 
					
						
							| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  |       Returns tools available in this context. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  |     Each tool is a 'ToolDef' or None for a separator in the toolbar, use ``None``. | 
					
						
							| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-13 08:13:13 +02:00
										 |  |  |     @staticmethod | 
					
						
							|  |  |  |     def _tool_class_from_space_type(space_type): | 
					
						
							|  |  |  |         return next( | 
					
						
							|  |  |  |             (cls for cls in ToolSelectPanelHelper.__subclasses__() | 
					
						
							|  |  |  |              if cls.bl_space_type == space_type), | 
					
						
							|  |  |  |             None | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-24 09:19:28 +02:00
										 |  |  |     @staticmethod | 
					
						
							|  |  |  |     def _icon_value_from_icon_handle(icon_name): | 
					
						
							|  |  |  |         import os | 
					
						
							|  |  |  |         if icon_name is not None: | 
					
						
							|  |  |  |             assert(type(icon_name) is str) | 
					
						
							|  |  |  |             icon_value = _icon_cache.get(icon_name) | 
					
						
							|  |  |  |             if icon_value is None: | 
					
						
							| 
									
										
										
										
											2018-04-25 14:05:48 +02:00
										 |  |  |                 dirname = bpy.utils.resource_path('LOCAL') | 
					
						
							| 
									
										
										
										
											2018-04-27 17:10:28 +03:00
										 |  |  |                 if not os.path.exists(dirname): | 
					
						
							| 
									
										
										
										
											2018-04-24 10:45:57 +02:00
										 |  |  |                     # TODO(campbell): use a better way of finding datafiles. | 
					
						
							| 
									
										
										
										
											2018-04-25 14:05:48 +02:00
										 |  |  |                     dirname = bpy.utils.resource_path('SYSTEM') | 
					
						
							| 
									
										
										
										
											2018-04-24 09:19:28 +02:00
										 |  |  |                 filename = os.path.join(dirname, "datafiles", "icons", icon_name + ".dat") | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     icon_value = bpy.app.icons.new_triangles_from_file(filename) | 
					
						
							|  |  |  |                 except Exception as ex: | 
					
						
							| 
									
										
										
										
											2018-04-27 15:34:54 +03:00
										 |  |  |                     if not os.path.exists(filename): | 
					
						
							| 
									
										
										
										
											2018-04-24 09:19:28 +02:00
										 |  |  |                         print("Missing icons:", filename, ex) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         print("Corrupt icon:", filename, ex) | 
					
						
							| 
									
										
										
										
											2018-04-30 13:55:15 +02:00
										 |  |  |                     # Use none as a fallback (avoids layout issues). | 
					
						
							|  |  |  |                     if icon_name != "none": | 
					
						
							|  |  |  |                         icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle("none") | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         icon_value = 0 | 
					
						
							| 
									
										
										
										
											2018-04-24 09:19:28 +02:00
										 |  |  |                 _icon_cache[icon_name] = icon_value | 
					
						
							|  |  |  |             return icon_value | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  |     @staticmethod | 
					
						
							|  |  |  |     def _tools_flatten(tools): | 
					
						
							| 
									
										
										
										
											2018-04-29 12:26:00 +02:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Flattens, skips None and calls generators. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  |         for item in tools: | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  |             if item is None: | 
					
						
							|  |  |  |                 yield None | 
					
						
							|  |  |  |             elif type(item) is tuple: | 
					
						
							|  |  |  |                 for sub_item in item: | 
					
						
							|  |  |  |                     if sub_item is None: | 
					
						
							|  |  |  |                         yield None | 
					
						
							|  |  |  |                     elif _item_is_fn(sub_item): | 
					
						
							|  |  |  |                         yield from sub_item(context) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         yield sub_item | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 if _item_is_fn(item): | 
					
						
							|  |  |  |                     yield from item(context) | 
					
						
							| 
									
										
										
										
											2017-11-03 16:30:51 +11:00
										 |  |  |                 else: | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  |                     yield item | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def _tools_flatten_with_tool_index(tools): | 
					
						
							|  |  |  |         for item in tools: | 
					
						
							|  |  |  |             if item is None: | 
					
						
							|  |  |  |                 yield None, -1 | 
					
						
							|  |  |  |             elif type(item) is tuple: | 
					
						
							|  |  |  |                 i = 0 | 
					
						
							|  |  |  |                 for sub_item in item: | 
					
						
							|  |  |  |                     if sub_item is None: | 
					
						
							|  |  |  |                         yield None | 
					
						
							|  |  |  |                     elif _item_is_fn(sub_item): | 
					
						
							|  |  |  |                         for item_dyn in sub_item(context): | 
					
						
							|  |  |  |                             yield item_dyn, i | 
					
						
							|  |  |  |                             i += 1 | 
					
						
							| 
									
										
										
										
											2018-04-29 12:26:00 +02:00
										 |  |  |                     else: | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  |                         yield sub_item, i | 
					
						
							|  |  |  |                         i += 1 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 if _item_is_fn(item): | 
					
						
							|  |  |  |                     for item_dyn in item(context): | 
					
						
							|  |  |  |                         yield item_dyn, -1 | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     yield item, -1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |     def _tool_get_active(context, space_type, mode, with_icon=False): | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Return the active Python tool definition and icon name. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         workspace = context.workspace | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |         cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  |         if cls is not None: | 
					
						
							| 
									
										
										
										
											2018-05-22 14:00:44 +02:00
										 |  |  |             tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type, mode) | 
					
						
							|  |  |  |             tool_active_text = getattr(tool_active, "name", None) | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |             for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context, mode)): | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  |                 if item is not None: | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |                     if item.text == tool_active_text: | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  |                         if with_icon: | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |                             icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon) | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  |                         else: | 
					
						
							|  |  |  |                             icon_value = 0 | 
					
						
							| 
									
										
										
										
											2018-05-22 14:00:44 +02:00
										 |  |  |                         return (item, tool_active, icon_value) | 
					
						
							|  |  |  |         return None, None, 0 | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							| 
									
										
										
										
											2018-05-16 18:59:43 +02:00
										 |  |  |     def _tool_get_by_name(context, space_type, text): | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Return the active Python tool definition and index (if in sub-group, else -1). | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2018-05-16 18:59:43 +02:00
										 |  |  |         cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  |         if cls is not None: | 
					
						
							|  |  |  |             for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)): | 
					
						
							|  |  |  |                 if item is not None: | 
					
						
							|  |  |  |                     if item.text == text: | 
					
						
							| 
									
										
										
										
											2018-05-30 22:15:10 +02:00
										 |  |  |                         return (cls, item, index) | 
					
						
							|  |  |  |         return None, None, -1 | 
					
						
							| 
									
										
										
										
											2017-11-03 16:30:51 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |     def _tool_active_from_context(context, space_type, mode=None, create=False): | 
					
						
							|  |  |  |         if space_type == 'VIEW_3D': | 
					
						
							|  |  |  |             if mode is None: | 
					
						
							| 
									
										
										
										
											2018-05-17 20:28:14 +02:00
										 |  |  |                 mode = context.mode | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |             tool = context.workspace.tools.from_space_view3d_mode(mode, create) | 
					
						
							|  |  |  |             if tool is not None: | 
					
						
							|  |  |  |                 return tool | 
					
						
							|  |  |  |         elif space_type == 'IMAGE_EDITOR': | 
					
						
							|  |  |  |             space_data = context.space_data | 
					
						
							|  |  |  |             if mode is None: | 
					
						
							|  |  |  |                 mode = space_data.mode | 
					
						
							|  |  |  |             tool = context.workspace.tools.from_space_image_mode(mode, create) | 
					
						
							|  |  |  |             if tool is not None: | 
					
						
							|  |  |  |                 return tool | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2017-11-03 16:30:51 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							| 
									
										
										
										
											2018-05-13 10:01:56 +02:00
										 |  |  |     def _tool_text_from_button(context): | 
					
						
							|  |  |  |         return context.button_operator.name | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  |     @classmethod | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  |     def _km_action_simple(cls, kc, context_mode, text, keymap_fn): | 
					
						
							| 
									
										
										
										
											2018-04-26 08:10:52 +02:00
										 |  |  |         if context_mode is None: | 
					
						
							|  |  |  |             context_mode = "All" | 
					
						
							|  |  |  |         km_idname = f"{cls.keymap_prefix} {context_mode}, {text}" | 
					
						
							| 
									
										
										
										
											2017-11-05 01:38:51 +11:00
										 |  |  |         km = kc.keymaps.get(km_idname) | 
					
						
							| 
									
										
										
										
											2018-04-30 12:14:46 +02:00
										 |  |  |         if km is None: | 
					
						
							|  |  |  |             km = kc.keymaps.new(km_idname, space_type=cls.bl_space_type, region_type='WINDOW') | 
					
						
							|  |  |  |             keymap_fn[0](km) | 
					
						
							|  |  |  |         keymap_fn[0] = km | 
					
						
							| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def register(cls): | 
					
						
							|  |  |  |         wm = bpy.context.window_manager | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # XXX, should we be manipulating the user-keyconfig on load? | 
					
						
							|  |  |  |         # Perhaps this should only add when keymap items don't already exist. | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # This needs some careful consideration. | 
					
						
							|  |  |  |         kc = wm.keyconfigs.user | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 16:30:51 +11:00
										 |  |  |         # Track which tool-group was last used for non-active groups. | 
					
						
							|  |  |  |         # Blender stores the active tool-group index. | 
					
						
							|  |  |  |         # | 
					
						
							| 
									
										
										
										
											2017-11-02 23:30:01 +11:00
										 |  |  |         # {tool_name_first: index_in_group, ...} | 
					
						
							|  |  |  |         cls._tool_group_active = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-26 22:04:48 +11:00
										 |  |  |         # ignore in background mode | 
					
						
							|  |  |  |         if kc is None: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-26 14:43:32 +02:00
										 |  |  |         for context_mode, tools in cls.tools_all(): | 
					
						
							| 
									
										
										
										
											2018-04-26 08:04:50 +02:00
										 |  |  |             for item_parent in tools: | 
					
						
							|  |  |  |                 if item_parent is None: | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  |                 for item in item_parent if (type(item_parent) is tuple) else (item_parent,): | 
					
						
							| 
									
										
										
										
											2018-04-29 12:26:00 +02:00
										 |  |  |                     # skip None or generator function | 
					
						
							|  |  |  |                     if item is None or _item_is_fn(item): | 
					
						
							| 
									
										
										
										
											2018-04-26 08:04:50 +02:00
										 |  |  |                         continue | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  |                     keymap_data = item.keymap | 
					
						
							| 
									
										
										
										
											2018-04-30 12:14:46 +02:00
										 |  |  |                     if keymap_data is not None and callable(keymap_data[0]): | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  |                         text = item.text | 
					
						
							|  |  |  |                         icon_name = item.icon | 
					
						
							| 
									
										
										
										
											2018-04-30 12:14:46 +02:00
										 |  |  |                         cls._km_action_simple(kc, context_mode, text, keymap_data) | 
					
						
							| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |     # ------------------------------------------------------------------------- | 
					
						
							|  |  |  |     # Layout Generators | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # Meaning of recieved values: | 
					
						
							|  |  |  |     # - Bool: True for a separator, otherwise False for regular tools. | 
					
						
							|  |  |  |     # - None: Signal to finish (complete any final operations, e.g. add padding). | 
					
						
							| 
									
										
										
										
											2017-10-21 16:19:48 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |     @staticmethod | 
					
						
							| 
									
										
										
										
											2018-06-06 08:31:31 +02:00
										 |  |  |     def _layout_generator_single_column(layout, scale_y): | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |         col = layout.column(align=True) | 
					
						
							|  |  |  |         col.scale_y = scale_y | 
					
						
							|  |  |  |         is_sep = False | 
					
						
							|  |  |  |         while True: | 
					
						
							|  |  |  |             if is_sep is True: | 
					
						
							|  |  |  |                 col = layout.column(align=True) | 
					
						
							|  |  |  |                 col.scale_y = scale_y | 
					
						
							|  |  |  |             elif is_sep is None: | 
					
						
							|  |  |  |                 yield None | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             is_sep = yield col | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							| 
									
										
										
										
											2018-06-06 08:31:31 +02:00
										 |  |  |     def _layout_generator_multi_columns(layout, column_count, scale_y): | 
					
						
							|  |  |  |         scale_x = scale_y * 1.1 | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |         column_last = column_count - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         col = layout.column(align=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         row = col.row(align=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         row.scale_x = scale_x | 
					
						
							|  |  |  |         row.scale_y = scale_y | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         is_sep = False | 
					
						
							|  |  |  |         column_index = 0 | 
					
						
							|  |  |  |         while True: | 
					
						
							|  |  |  |             if is_sep is True: | 
					
						
							|  |  |  |                 if column_index != column_last: | 
					
						
							|  |  |  |                     row.label("") | 
					
						
							|  |  |  |                 col = layout.column(align=True) | 
					
						
							|  |  |  |                 row = col.row(align=True) | 
					
						
							|  |  |  |                 row.scale_x = scale_x | 
					
						
							|  |  |  |                 row.scale_y = scale_y | 
					
						
							|  |  |  |                 column_index = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             is_sep = yield row | 
					
						
							|  |  |  |             if is_sep is None: | 
					
						
							|  |  |  |                 if column_index == column_last: | 
					
						
							|  |  |  |                     row.label("") | 
					
						
							|  |  |  |                     yield None | 
					
						
							|  |  |  |                     return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if column_index == column_count: | 
					
						
							|  |  |  |                 column_index = 0 | 
					
						
							|  |  |  |                 row = col.row(align=True) | 
					
						
							|  |  |  |                 row.scale_x = scale_x | 
					
						
							|  |  |  |                 row.scale_y = scale_y | 
					
						
							|  |  |  |             column_index += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							| 
									
										
										
										
											2018-06-06 08:31:31 +02:00
										 |  |  |     def _layout_generator_detect_from_region(layout, region, scale_y): | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Choose an appropriate layout for the toolbar. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # Currently this just checks the width, | 
					
						
							|  |  |  |         # we could have different layouts as preferences too. | 
					
						
							| 
									
										
										
										
											2018-04-28 20:48:47 +02:00
										 |  |  |         system = bpy.context.user_preferences.system | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |         view2d = region.view2d | 
					
						
							| 
									
										
										
										
											2018-04-28 20:48:47 +02:00
										 |  |  |         view2d_scale = ( | 
					
						
							| 
									
										
										
										
											2018-04-24 16:33:38 +02:00
										 |  |  |             view2d.region_to_view(1.0, 0.0)[0] - | 
					
						
							|  |  |  |             view2d.region_to_view(0.0, 0.0)[0] | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2018-04-28 20:48:47 +02:00
										 |  |  |         width_scale = region.width * view2d_scale / system.ui_scale | 
					
						
							| 
									
										
										
										
											2018-04-24 16:33:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 18:20:48 +02:00
										 |  |  |         if width_scale > 120.0: | 
					
						
							| 
									
										
										
										
											2018-04-27 17:55:17 +02:00
										 |  |  |             show_text = True | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |             column_count = 1 | 
					
						
							| 
									
										
										
										
											2018-04-27 17:55:17 +02:00
										 |  |  |         else: | 
					
						
							|  |  |  |             show_text = False | 
					
						
							| 
									
										
										
										
											2018-04-27 18:20:48 +02:00
										 |  |  |             # 2 column layout, disabled | 
					
						
							|  |  |  |             if width_scale > 80.0: | 
					
						
							| 
									
										
										
										
											2018-04-27 17:55:17 +02:00
										 |  |  |                 column_count = 2 | 
					
						
							|  |  |  |                 use_columns = True | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |                 column_count = 1 | 
					
						
							| 
									
										
										
										
											2018-04-27 17:55:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |         if column_count == 1: | 
					
						
							| 
									
										
										
										
											2018-06-06 08:31:31 +02:00
										 |  |  |             ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout, scale_y=scale_y) | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2018-06-06 08:31:31 +02:00
										 |  |  |             ui_gen = ToolSelectPanelHelper._layout_generator_multi_columns(layout, column_count=column_count, scale_y=scale_y) | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return ui_gen, show_text | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-18 21:16:57 +02:00
										 |  |  |     @classmethod | 
					
						
							| 
									
										
										
										
											2018-06-06 08:31:31 +02:00
										 |  |  |     def draw_cls(cls, layout, context, detect_layout=True, scale_y=2.0): | 
					
						
							| 
									
										
										
										
											2018-05-18 21:16:57 +02:00
										 |  |  |         # Use a classmethod so it can be called outside of a panel context. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |         # XXX, this UI isn't very nice. | 
					
						
							|  |  |  |         # We might need to create new button types for this. | 
					
						
							|  |  |  |         # Since we probably want: | 
					
						
							|  |  |  |         # - tool-tips that include multiple key shortcuts. | 
					
						
							|  |  |  |         # - ability to click and hold to expose sub-tools. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |         space_type = context.space_data.type | 
					
						
							|  |  |  |         tool_active_text = getattr( | 
					
						
							|  |  |  |             ToolSelectPanelHelper._tool_active_from_context(context, space_type), | 
					
						
							|  |  |  |             "name", None, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-18 22:27:59 +02:00
										 |  |  |         if detect_layout: | 
					
						
							| 
									
										
										
										
											2018-06-06 08:31:31 +02:00
										 |  |  |             ui_gen, show_text = cls._layout_generator_detect_from_region(layout, context.region, scale_y) | 
					
						
							| 
									
										
										
										
											2018-05-18 22:27:59 +02:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2018-06-06 08:31:31 +02:00
										 |  |  |             ui_gen = ToolSelectPanelHelper._layout_generator_single_column(layout, scale_y) | 
					
						
							| 
									
										
										
										
											2018-05-18 22:27:59 +02:00
										 |  |  |             show_text = True | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Start iteration | 
					
						
							|  |  |  |         ui_gen.send(None) | 
					
						
							| 
									
										
										
										
											2018-04-27 17:55:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-18 21:16:57 +02:00
										 |  |  |         for item in cls.tools_from_context(context): | 
					
						
							| 
									
										
										
										
											2018-05-13 08:32:47 +02:00
										 |  |  |             if item is None: | 
					
						
							|  |  |  |                 ui_gen.send(True) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if type(item) is tuple: | 
					
						
							|  |  |  |                 is_active = False | 
					
						
							|  |  |  |                 i = 0 | 
					
						
							|  |  |  |                 for i, sub_item in enumerate(item): | 
					
						
							|  |  |  |                     if sub_item is None: | 
					
						
							|  |  |  |                         continue | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |                     is_active = (sub_item.text == tool_active_text) | 
					
						
							| 
									
										
										
										
											2018-04-29 12:26:00 +02:00
										 |  |  |                     if is_active: | 
					
						
							| 
									
										
										
										
											2018-05-13 08:32:47 +02:00
										 |  |  |                         index = i | 
					
						
							|  |  |  |                         break | 
					
						
							|  |  |  |                 del i, sub_item | 
					
						
							| 
									
										
										
										
											2018-04-29 12:26:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-13 08:32:47 +02:00
										 |  |  |                 if is_active: | 
					
						
							|  |  |  |                     # not ideal, write this every time :S | 
					
						
							| 
									
										
										
										
											2018-05-18 21:16:57 +02:00
										 |  |  |                     cls._tool_group_active[item[0].text] = index | 
					
						
							| 
									
										
										
										
											2018-04-29 12:26:00 +02:00
										 |  |  |                 else: | 
					
						
							| 
									
										
										
										
											2018-05-18 21:16:57 +02:00
										 |  |  |                     index = cls._tool_group_active.get(item[0].text, 0) | 
					
						
							| 
									
										
										
										
											2018-04-29 12:26:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-13 08:32:47 +02:00
										 |  |  |                 item = item[index] | 
					
						
							|  |  |  |                 use_menu = True | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 index = -1 | 
					
						
							|  |  |  |                 use_menu = False | 
					
						
							| 
									
										
										
										
											2018-04-29 14:30:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |             is_active = (item.text == tool_active_text) | 
					
						
							| 
									
										
										
										
											2018-05-18 07:24:17 +02:00
										 |  |  |             icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon) | 
					
						
							| 
									
										
										
										
											2018-04-29 12:26:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-13 08:32:47 +02:00
										 |  |  |             sub = ui_gen.send(False) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if use_menu: | 
					
						
							| 
									
										
										
										
											2018-05-13 10:01:56 +02:00
										 |  |  |                 sub.operator_menu_hold( | 
					
						
							|  |  |  |                     "wm.tool_set_by_name", | 
					
						
							| 
									
										
										
										
											2018-05-13 08:32:47 +02:00
										 |  |  |                     text=item.text if show_text else "", | 
					
						
							|  |  |  |                     depress=is_active, | 
					
						
							|  |  |  |                     menu="WM_MT_toolsystem_submenu", | 
					
						
							|  |  |  |                     icon_value=icon_value, | 
					
						
							| 
									
										
										
										
											2018-05-13 10:01:56 +02:00
										 |  |  |                 ).name = item.text | 
					
						
							| 
									
										
										
										
											2018-05-13 08:32:47 +02:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2018-05-13 10:01:56 +02:00
										 |  |  |                 sub.operator( | 
					
						
							|  |  |  |                     "wm.tool_set_by_name", | 
					
						
							| 
									
										
										
										
											2018-05-13 08:32:47 +02:00
										 |  |  |                     text=item.text if show_text else "", | 
					
						
							|  |  |  |                     depress=is_active, | 
					
						
							|  |  |  |                     icon_value=icon_value, | 
					
						
							| 
									
										
										
										
											2018-05-13 10:01:56 +02:00
										 |  |  |                 ).name = item.text | 
					
						
							| 
									
										
										
										
											2018-04-28 10:51:05 +02:00
										 |  |  |         # Signal to finish any remaining layout edits. | 
					
						
							|  |  |  |         ui_gen.send(None) | 
					
						
							| 
									
										
										
										
											2018-04-27 17:55:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-18 21:16:57 +02:00
										 |  |  |     def draw(self, context): | 
					
						
							|  |  |  |         self.draw_cls(self.layout, context) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 10:49:20 +02:00
										 |  |  |     @staticmethod | 
					
						
							|  |  |  |     def draw_active_tool_header(context, layout): | 
					
						
							| 
									
										
										
										
											2018-05-16 18:41:11 +02:00
										 |  |  |         # BAD DESIGN WARNING: last used tool | 
					
						
							|  |  |  |         workspace = context.workspace | 
					
						
							|  |  |  |         space_type = workspace.tools_space_type | 
					
						
							|  |  |  |         mode = workspace.tools_mode | 
					
						
							| 
									
										
										
										
											2018-05-22 14:00:44 +02:00
										 |  |  |         item, tool, icon_value = ToolSelectPanelHelper._tool_get_active(context, space_type, mode, with_icon=True) | 
					
						
							| 
									
										
										
										
											2018-04-27 10:49:20 +02:00
										 |  |  |         if item is None: | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2018-04-29 17:49:39 +02:00
										 |  |  |         # Note: we could show 'item.text' here but it makes the layout jitter when switcuing tools. | 
					
						
							|  |  |  |         layout.label(" ", icon_value=icon_value) | 
					
						
							| 
									
										
										
										
											2018-04-27 14:13:16 +02:00
										 |  |  |         draw_settings = item.draw_settings | 
					
						
							|  |  |  |         if draw_settings is not None: | 
					
						
							| 
									
										
										
										
											2018-05-22 14:00:44 +02:00
										 |  |  |             draw_settings(context, layout, tool) | 
					
						
							| 
									
										
										
										
											2018-04-27 14:13:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 10:49:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  | # The purpose of this menu is to be a generic popup to select between tools | 
					
						
							|  |  |  | # in cases when a single tool allows to select alternative tools. | 
					
						
							|  |  |  | class WM_MT_toolsystem_submenu(Menu): | 
					
						
							|  |  |  |     bl_label = "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def _tool_group_from_button(context): | 
					
						
							|  |  |  |         # Lookup the tool definitions based on the space-type. | 
					
						
							| 
									
										
										
										
											2018-05-13 08:13:13 +02:00
										 |  |  |         cls = ToolSelectPanelHelper._tool_class_from_space_type(context.space_data.type) | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  |         if cls is not None: | 
					
						
							| 
									
										
										
										
											2018-05-13 10:01:56 +02:00
										 |  |  |             button_text = ToolSelectPanelHelper._tool_text_from_button(context) | 
					
						
							| 
									
										
										
										
											2018-04-29 16:24:40 +02:00
										 |  |  |             for item_group in cls.tools_from_context(context): | 
					
						
							|  |  |  |                 if type(item_group) is tuple: | 
					
						
							| 
									
										
										
										
											2018-05-13 10:01:56 +02:00
										 |  |  |                     for sub_item in item_group: | 
					
						
							|  |  |  |                         if sub_item.text == button_text: | 
					
						
							|  |  |  |                             return cls, item_group | 
					
						
							|  |  |  |         return None, None | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def draw(self, context): | 
					
						
							|  |  |  |         layout = self.layout | 
					
						
							| 
									
										
										
										
											2018-04-24 09:19:28 +02:00
										 |  |  |         layout.scale_y = 2.0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-13 10:01:56 +02:00
										 |  |  |         cls, item_group = self._tool_group_from_button(context) | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  |         if item_group is None: | 
					
						
							|  |  |  |             # Should never happen, just in case | 
					
						
							| 
									
										
										
										
											2017-11-03 16:30:51 +11:00
										 |  |  |             layout.label("Unable to find toolbar group") | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for item in item_group: | 
					
						
							|  |  |  |             if item is None: | 
					
						
							|  |  |  |                 layout.separator() | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2018-05-18 07:24:17 +02:00
										 |  |  |             icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon) | 
					
						
							| 
									
										
										
										
											2018-05-16 18:59:43 +02:00
										 |  |  |             layout.operator( | 
					
						
							| 
									
										
										
										
											2018-05-13 10:01:56 +02:00
										 |  |  |                 "wm.tool_set_by_name", | 
					
						
							| 
									
										
										
										
											2018-04-27 13:23:29 +02:00
										 |  |  |                 text=item.text, | 
					
						
							| 
									
										
										
										
											2018-04-24 09:19:28 +02:00
										 |  |  |                 icon_value=icon_value, | 
					
						
							| 
									
										
										
										
											2018-05-13 10:01:56 +02:00
										 |  |  |             ).name = item.text | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-30 22:15:10 +02:00
										 |  |  | def _activate_by_item(context, space_type, item, index): | 
					
						
							|  |  |  |     tool = ToolSelectPanelHelper._tool_active_from_context(context, space_type, create=True) | 
					
						
							|  |  |  |     tool.setup( | 
					
						
							|  |  |  |         name=item.text, | 
					
						
							|  |  |  |         keymap=item.keymap[0].name if item.keymap is not None else "", | 
					
						
							|  |  |  |         cursor=item.cursor or 'DEFAULT', | 
					
						
							|  |  |  |         manipulator_group=item.widget or "", | 
					
						
							|  |  |  |         data_block=item.data_block or "", | 
					
						
							|  |  |  |         index=index, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-16 18:59:43 +02:00
										 |  |  | def activate_by_name(context, space_type, text): | 
					
						
							| 
									
										
										
										
											2018-05-30 22:15:10 +02:00
										 |  |  |     cls, item, index = ToolSelectPanelHelper._tool_get_by_name(context, space_type, text) | 
					
						
							|  |  |  |     if item is None: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     _activate_by_item(context, space_type, item, index) | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def activate_by_name_or_cycle(context, space_type, text, offset=1): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Only cycle when the active tool is activated again. | 
					
						
							|  |  |  |     cls, item, index = ToolSelectPanelHelper._tool_get_by_name(context, space_type, text) | 
					
						
							|  |  |  |     if item is None: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tool_active = ToolSelectPanelHelper._tool_active_from_context(context, space_type) | 
					
						
							|  |  |  |     text_active = getattr(tool_active, "name", None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     text_current = "" | 
					
						
							|  |  |  |     for item_group in cls.tools_from_context(context): | 
					
						
							|  |  |  |         if type(item_group) is tuple: | 
					
						
							|  |  |  |             index_current = cls._tool_group_active.get(item_group[0].text, 0) | 
					
						
							|  |  |  |             ok = False | 
					
						
							|  |  |  |             for i, sub_item in enumerate(item_group): | 
					
						
							|  |  |  |                 if sub_item.text == text: | 
					
						
							|  |  |  |                     text_current = item_group[index_current].text | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             if text_current: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if text_current == "": | 
					
						
							|  |  |  |         return activate_by_name(context, space_type, text) | 
					
						
							|  |  |  |     if text_active != text_current: | 
					
						
							|  |  |  |         return activate_by_name(context, space_type, text_current) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     index_found = (tool_active.index + offset) % len(item_group) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cls._tool_group_active[item_group[0].text] = index_found | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     item_found = item_group[index_found] | 
					
						
							|  |  |  |     _activate_by_item(context, space_type, item_found, index_found) | 
					
						
							|  |  |  |     return True | 
					
						
							| 
									
										
										
										
											2018-05-13 08:59:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-21 10:43:15 +02:00
										 |  |  | def keymap_from_context(context, space_type): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Keymap for popup toolbar, currently generated each time. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     use_simple_keymap = False | 
					
						
							|  |  |  |     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') | 
					
						
							|  |  |  |     for kmi in keymap.keymap_items: | 
					
						
							|  |  |  |         keymap.keymap_items.remove(kmi) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     items = [] | 
					
						
							|  |  |  |     cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) | 
					
						
							|  |  |  |     for i, item in enumerate( | 
					
						
							|  |  |  |             ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context)) | 
					
						
							|  |  |  |     ): | 
					
						
							|  |  |  |         if item is not None: | 
					
						
							|  |  |  |             if use_simple_keymap: | 
					
						
							|  |  |  |                 # Simply assign a key from A-Z | 
					
						
							|  |  |  |                 items.append(((chr(ord('A') + i)), item.text)) | 
					
						
							|  |  |  |                 kmi = keymap.keymap_items.new("wm.tool_set_by_name", key, 'PRESS') | 
					
						
							|  |  |  |                 kmi.properties.name = item.text | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-21 13:06:59 +02:00
										 |  |  |             if not item.keymap: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Only check the first item in the tools key-map (a little arbitrary). | 
					
						
							|  |  |  |             kmi_first = item.keymap[0].keymap_items[0] | 
					
						
							| 
									
										
										
										
											2018-05-21 11:54:47 +02:00
										 |  |  |             kmi_found = wm.keyconfigs.find_item_from_operator( | 
					
						
							| 
									
										
										
										
											2018-05-21 10:43:15 +02:00
										 |  |  |                 idname=kmi_first.idname, | 
					
						
							|  |  |  |                 # properties=kmi_first.properties,  # prevents matches, don't use. | 
					
						
							| 
									
										
										
										
											2018-05-21 11:54:47 +02:00
										 |  |  |             )[1] | 
					
						
							| 
									
										
										
										
											2018-05-21 10:43:15 +02:00
										 |  |  |             if kmi_found is not None: | 
					
						
							|  |  |  |                 kmi_found_type = kmi_found.type | 
					
						
							|  |  |  |                 # Only for single keys. | 
					
						
							|  |  |  |                 if len(kmi_found_type) == 1: | 
					
						
							|  |  |  |                     kmi = keymap.keymap_items.new( | 
					
						
							|  |  |  |                         idname="wm.tool_set_by_name", | 
					
						
							|  |  |  |                         type=kmi_found_type, | 
					
						
							|  |  |  |                         value='PRESS', | 
					
						
							|  |  |  |                         any=kmi_found.any, | 
					
						
							|  |  |  |                         shift=kmi_found.shift, | 
					
						
							|  |  |  |                         ctrl=kmi_found.ctrl, | 
					
						
							|  |  |  |                         alt=kmi_found.alt, | 
					
						
							|  |  |  |                         oskey=kmi_found.oskey, | 
					
						
							|  |  |  |                         key_modifier=kmi_found.key_modifier, | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                     kmi.properties.name = item.text | 
					
						
							| 
									
										
										
										
											2018-05-21 11:54:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-21 10:43:15 +02:00
										 |  |  |     wm.keyconfigs.update() | 
					
						
							|  |  |  |     return keymap | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-05 16:35:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-02 23:05:13 +11:00
										 |  |  | classes = ( | 
					
						
							|  |  |  |     WM_MT_toolsystem_submenu, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__":  # only for live edit. | 
					
						
							|  |  |  |     from bpy.utils import register_class | 
					
						
							|  |  |  |     for cls in classes: | 
					
						
							|  |  |  |         register_class(cls) |