diff options
author | Campbell Barton <ideasman42@gmail.com> | 2018-05-16 19:41:11 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2018-05-17 16:57:33 +0300 |
commit | edf6676a77b30290918e60547544bc1a6f7a8838 (patch) | |
tree | 26012f315c75686553e6be87b73ad270b98eb01a /release | |
parent | 20cc14e2b7551bb043472174b8be79d8aaa4df3d (diff) |
Tool System: per space/mode tool support
This patch adds support for:
- Per space-type tools (3D view and edit).
- Per mode tools (object, edit, weight-paint .. etc).
The top-bar shows the last activated tools options, this is a design
issue with using a global topbar to show per-space settings.
See D3395
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/startup/bl_operators/wm.py | 13 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_toolsystem_common.py | 78 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_toolsystem_toolbar.py | 109 |
3 files changed, 163 insertions, 37 deletions
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index a9d766b29e2..970eff34026 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -2335,10 +2335,21 @@ class WM_OT_tool_set_by_name(Operator): name="Text", description="Display name of the tool", ) + space_type = EnumProperty( + name="Type", + items=tuple( + (e.identifier, e.name, "", e. value) + for e in bpy.types.Space.bl_rna.properties["type"].enum_items + ), + default='EMPTY', + ) def execute(self, context): from bl_ui.space_toolsystem_common import activate_by_name - if activate_by_name(context, context.space_data.type, self.name): + space_type = self.space_type + if space_type == 'EMPTY': + space_type = context.space_data.type + if activate_by_name(context, space_type, self.name): return {'FINISHED'} else: self.report({'WARNING'}, f"Tool {self.name!r} not found.") diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py index b58bff7cf32..ad5c970a6d5 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_common.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -140,7 +140,7 @@ class ToolSelectPanelHelper: The text prefix for each key-map for this spaces tools. - tools_all(): Returns (context_mode, tools) tuple pair for all tools defined. - - tools_from_context(context): + - tools_from_context(context, mode=None): Returns tools available in this context. Each tool is a 'ToolDef' or None for a separator in the toolbar, use ``None``. @@ -230,23 +230,23 @@ class ToolSelectPanelHelper: yield item, -1 @staticmethod - def _tool_get_active(context, with_icon=False): + def _tool_get_active(context, space_type, mode, with_icon=False): """ Return the active Python tool definition and icon name. """ workspace = context.workspace - cls = ToolSelectPanelHelper._tool_class_from_space_type(workspace.tool_space_type) + cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) if cls is not None: - tool_def_active, index_active = ToolSelectPanelHelper._tool_vars_from_active_with_index(context) + tool_active_text = getattr( + ToolSelectPanelHelper._tool_active_from_context(context, space_type, mode), + "name", None) - context_mode = context.mode - for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context)): + for item in ToolSelectPanelHelper._tools_flatten(cls.tools_from_context(context, mode)): if item is not None: - tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item, context_mode) - if (tool_def == tool_def_active): + if item.text == tool_active_text: if with_icon: - icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(icon_name) + icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon) else: icon_value = 0 return (item, icon_value) @@ -259,7 +259,6 @@ class ToolSelectPanelHelper: """ cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) if cls is not None: - context_mode = context.mode for item, index in ToolSelectPanelHelper._tools_flatten_with_tool_index(cls.tools_from_context(context)): if item is not None: if item.text == text: @@ -267,7 +266,7 @@ class ToolSelectPanelHelper: return None, -1 @staticmethod - def _tool_vars_from_def(item, context_mode): + def _tool_vars_from_def(item): # For now be strict about whats in this dict # prevent accidental adding unknown keys. text = item.text @@ -282,16 +281,22 @@ class ToolSelectPanelHelper: return (km_idname, mp_idname, datablock_idname), icon_name @staticmethod - def _tool_vars_from_active_with_index(context): - workspace = context.workspace - return ( - ( - workspace.tool_keymap or None, - workspace.tool_manipulator_group or None, - workspace.tool_data_block or None, - ), - workspace.tool_index, - ) + def _tool_active_from_context(context, space_type, mode=None, create=False): + if space_type == 'VIEW_3D': + if mode is None: + obj = context.active_object + mode = obj.mode if obj is not None else 'OBJECT' + 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 @staticmethod def _tool_text_from_button(context): @@ -445,8 +450,11 @@ class ToolSelectPanelHelper: # - tool-tips that include multiple key shortcuts. # - ability to click and hold to expose sub-tools. - context_mode = context.mode - tool_def_active, index_active = ToolSelectPanelHelper._tool_vars_from_active_with_index(context) + space_type = context.space_data.type + tool_active_text = getattr( + ToolSelectPanelHelper._tool_active_from_context(context, space_type), + "name", None, + ) ui_gen, show_text = self._layout_generator_detect_from_region(self.layout, context.region) @@ -464,8 +472,7 @@ class ToolSelectPanelHelper: for i, sub_item in enumerate(item): if sub_item is None: continue - tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(sub_item, context_mode) - is_active = (tool_def == tool_def_active) + is_active = (sub_item.text == tool_active_text) if is_active: index = i break @@ -483,8 +490,8 @@ class ToolSelectPanelHelper: index = -1 use_menu = False - tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item, context_mode) - is_active = (tool_def == tool_def_active) + tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item) + is_active = (item.text == tool_active_text) icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(icon_name) @@ -510,7 +517,11 @@ class ToolSelectPanelHelper: @staticmethod def draw_active_tool_header(context, layout): - item, icon_value = ToolSelectPanelHelper._tool_get_active(context, with_icon=True) + # BAD DESIGN WARNING: last used tool + workspace = context.workspace + space_type = workspace.tools_space_type + mode = workspace.tools_mode + item, icon_value = ToolSelectPanelHelper._tool_get_active(context, space_type, mode, with_icon=True) if item is None: return # Note: we could show 'item.text' here but it makes the layout jitter when switcuing tools. @@ -527,7 +538,6 @@ class WM_MT_toolsystem_submenu(Menu): @staticmethod def _tool_group_from_button(context): - context_mode = context.mode # Lookup the tool definitions based on the space-type. cls = ToolSelectPanelHelper._tool_class_from_space_type(context.space_data.type) if cls is not None: @@ -540,7 +550,6 @@ class WM_MT_toolsystem_submenu(Menu): return None, None def draw(self, context): - context_mode = context.mode layout = self.layout layout.scale_y = 2.0 @@ -554,7 +563,7 @@ class WM_MT_toolsystem_submenu(Menu): if item is None: layout.separator() continue - tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item, context_mode) + tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item) icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(icon_name) layout.operator( "wm.tool_set_by_name", @@ -566,9 +575,10 @@ class WM_MT_toolsystem_submenu(Menu): def activate_by_name(context, space_type, text): item, index = ToolSelectPanelHelper._tool_get_by_name(context, space_type, text) if item is not None: - context_mode = context.mode - tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item, context_mode) - bpy.ops.wm.tool_set( + tool = ToolSelectPanelHelper._tool_active_from_context(context, space_type, create=True) + tool_def, icon_name = ToolSelectPanelHelper._tool_vars_from_def(item) + tool.setup( + name=text, keymap=tool_def[0] or "", manipulator_group=tool_def[1] or "", data_block=tool_def[2] or "", diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index a0360c0900b..4a368bd712d 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -777,6 +777,108 @@ class _defs_weight_paint: ) +class _defs_uv_select: + + @ToolDef.from_fn + def border(): + return dict( + text="Select Border", + icon="ops.generic.select_border", + widget=None, + keymap=( + ("uv.select_border", + dict(deselect=False), + dict(type='EVT_TWEAK_A', value='ANY')), + # ("uv.select_border", + # dict(deselect=True), + # dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)), + ), + ) + + @ToolDef.from_fn + def circle(): + return dict( + text="Select Circle", + icon="ops.generic.select_circle", + widget=None, + keymap=( + ("uv.select_circle", + dict(), # dict(deselect=False), + dict(type='ACTIONMOUSE', value='PRESS')), + # ("uv.select_circle", + # dict(deselect=True), + # dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)), + ), + ) + + @ToolDef.from_fn + def lasso(): + return dict( + text="Select Lasso", + icon="ops.generic.select_lasso", + widget=None, + keymap=( + ("uv.select_lasso", + dict(deselect=False), + dict(type='EVT_TWEAK_A', value='ANY')), + # ("uv.select_lasso", + # dict(deselect=True), + # dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)), + ), + ) + + +class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel): + bl_space_type = 'IMAGE_EDITOR' + bl_region_type = 'TOOLS' + bl_category = "Tools" + bl_label = "Tools" # not visible + bl_options = {'HIDE_HEADER'} + + # Satisfy the 'ToolSelectPanelHelper' API. + keymap_prefix = "Image Editor Tool: " + + @classmethod + def tools_from_context(cls, context, mode=None): + if mode is None: + mode = context.space_data.mode + for tools in (cls._tools[None], cls._tools.get(mode, ())): + for item in tools: + if not (type(item) is ToolDef) and callable(item): + yield from item(context) + else: + yield item + + @classmethod + def tools_all(cls): + yield from cls._tools.items() + + # for reuse + _tools_select = ( + ( + _defs_uv_select.border, + _defs_uv_select.circle, + _defs_uv_select.lasso, + ), + ) + + _tools = { + None: [ + # for all modes + ], + 'VIEW': [ + *_tools_select, + + ], + 'MASK': [ + None, + ], + 'PAINT': [ + _defs_texture_paint.generate_from_brushes, + ], + } + + class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'TOOLS' @@ -788,8 +890,10 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): keymap_prefix = "3D View Tool: " @classmethod - def tools_from_context(cls, context): - for tools in (cls._tools[None], cls._tools.get(context.mode, ())): + def tools_from_context(cls, context, mode=None): + if mode is None: + mode = context.mode + for tools in (cls._tools[None], cls._tools.get(mode, ())): for item in tools: if not (type(item) is ToolDef) and callable(item): yield from item(context) @@ -934,6 +1038,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): classes = ( + IMAGE_PT_tools_active, VIEW3D_PT_tools_active, ) |