[Bf-blender-cvs] [1ca3e1a91db] blender2.8: UI: support nested tools in toolbar

Campbell Barton noreply at git.blender.org
Thu Nov 2 13:05:43 CET 2017


Commit: 1ca3e1a91dbb4bbd99d8d8275e2a9c8dc0505d1c
Author: Campbell Barton
Date:   Thu Nov 2 23:05:13 2017 +1100
Branches: blender2.8
https://developer.blender.org/rB1ca3e1a91dbb4bbd99d8d8275e2a9c8dc0505d1c

UI: support nested tools in toolbar

===================================================================

M	release/scripts/startup/bl_ui/__init__.py
M	release/scripts/startup/bl_ui/space_toolsystem_common.py
M	release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
M	source/blender/makesdna/DNA_workspace_types.h
M	source/blender/makesrna/intern/rna_workspace.c
M	source/blender/windowmanager/intern/wm_operators.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index a12fd6352ea..037fe9618ec 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -68,6 +68,7 @@ _modules = [
     # Generic Space Modules
     #
     # Depends on DNA_WORKSPACE_TOOL (C define).
+    "space_toolsystem_common",
     "space_toolsystem_toolbar",
 
     "space_clip",
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
index 1dade5b6735..69f4b0bbf2a 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_common.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -18,6 +18,9 @@
 
 # <pep8 compliant>
 import bpy
+from bpy.types import (
+    Menu,
+)
 
 __all__ = (
     "ToolSelectPanelHelper",
@@ -48,6 +51,19 @@ class ToolSelectPanelHelper:
         an optional triple of: ``(operator_id, operator_properties, keymap_item_args)``
     """
 
+    @staticmethod
+    def _tool_is_group(tool):
+        return type(tool[0]) is not str
+
+    @staticmethod
+    def _tools_flatten(tools):
+        for item in tools:
+            if ToolSelectPanelHelper._tool_is_group(item):
+                for sub_item in item:
+                    yield sub_item
+            else:
+                yield item
+
     @classmethod
     def _km_actionmouse_simple(cls, kc, text, actions):
 
@@ -85,7 +101,7 @@ class ToolSelectPanelHelper:
         if kc is None:
             return
 
-        for t in cls.tools_all():
+        for t in ToolSelectPanelHelper._tools_flatten(cls.tools_all()):
             text, mp_idname, actions = t
             if actions is not None:
                 km, km_idname = cls._km_actionmouse_simple(kc, text, actions)
@@ -101,6 +117,7 @@ class ToolSelectPanelHelper:
         workspace = context.workspace
         km_idname_active = workspace.tool_keymap or None
         mp_idname_active = workspace.tool_manipulator_group or None
+        index_active = workspace.tool_index
         layout = self.layout
 
         for tool_items in self.tools_from_context(context):
@@ -110,22 +127,122 @@ class ToolSelectPanelHelper:
                     if item is None:
                         col = layout.column(align=True)
                         continue
-                    text, mp_idname, actions = item
 
-                    if actions is not None:
-                        km, km_idname = self._tool_keymap[text]
+                    if self._tool_is_group(item):
+                        index = 0
+                        is_active = False
+                        for i, sub_item in enumerate(item):
+                            text, mp_idname, actions = sub_item
+                            km, km_idname = (None, None) if actions is None else self._tool_keymap[text]
+                            is_active = (
+                                km_idname_active == km_idname and
+                                mp_idname_active == mp_idname
+                            )
+                            if is_active:
+                                index = i
+                                break
+                        del i, sub_item
+                        item = item[index]
+                        use_menu = True
                     else:
-                        km = None
-                        km_idname = None
-
-                    props = col.operator(
-                        "wm.tool_set",
-                        text=text,
-                        depress=(
-                            km_idname_active == km_idname and
-                            mp_idname_active == mp_idname
-                        ),
+                        index = -1
+                        use_menu = False
+
+                    text, mp_idname, actions = item
+                    km, km_idname = (None, None) if actions is None else self._tool_keymap[text]
+                    is_active = (
+                        km_idname_active == km_idname and
+                        mp_idname_active == mp_idname
                     )
 
+                    if use_menu:
+                        props = col.operator_menu_hold(
+                            "wm.tool_set",
+                            text=text,
+                            depress=is_active,
+                            menu="WM_MT_toolsystem_submenu",
+                        )
+                    else:
+                        props = col.operator(
+                            "wm.tool_set",
+                            text=text,
+                            depress=is_active,
+                        )
+
                     props.keymap = km_idname or ""
                     props.manipulator_group = mp_idname or ""
+                    props.index = index
+
+    def tools_from_context(cls, context):
+        return (cls._tools[None], cls._tools.get(context.mode, ()))
+
+
+# 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.
+        space_type = context.space_data.type
+        cls = next(
+            (cls for cls in ToolSelectPanelHelper.__subclasses__()
+             if cls.bl_space_type == space_type),
+            None
+        )
+        if cls is not None:
+            props = context.button_operator
+            km_idname_button = props.keymap or None
+            mp_idname_button = props.manipulator_group or None
+            index_button = props.index
+
+            for item_items in cls.tools_from_context(context):
+                for item_group in item_items:
+                    if (item_group is not None) and ToolSelectPanelHelper._tool_is_group(item_group):
+                        if index_button < len(item_group):
+                            item = item_group[index_button]
+                            text, mp_idname, actions = item
+                            km, km_idname = (None, None) if actions is None else cls._tool_keymap[text]
+                            is_active = (
+                                km_idname_button == km_idname and
+                                mp_idname_button == mp_idname
+                            )
+                            if is_active:
+                                return cls, item_group, index_button
+        return None, None, -1
+
+    def draw(self, context):
+        layout = self.layout
+        cls, item_group, index_active = self._tool_group_from_button(context)
+        if item_group is None:
+            # Should never happen, just in case
+            layout.label(f"Unable to find toolbar group")
+            return
+
+        index = 0
+        for item in item_group:
+            if item is None:
+                layout.separator()
+                continue
+            text, mp_idname, actions = item
+            km, km_idname = (None, None) if actions is None else cls._tool_keymap[text]
+
+            props = layout.operator(
+                "wm.tool_set",
+                text=text,
+            )
+            props.keymap = km_idname or ""
+            props.manipulator_group = mp_idname or ""
+            props.index = index
+            index += 1
+
+
+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)
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 71e41850a51..6667eb566c2 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -66,20 +66,25 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
         None: [
             ("Cursor", None,
              (("view3d.cursor3d", dict(), dict(type='ACTIONMOUSE', value='CLICK')),)),
-            ("Select Border", None, (
-                ("view3d.select_border", dict(deselect=False), dict(type='EVT_TWEAK_A', value='ANY')),
-                ("view3d.select_border", dict(deselect=True), dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
-            )),
-            ("Select Circle", None, (
-                ("view3d.select_circle", dict(deselect=False), dict(type='ACTIONMOUSE', value='PRESS')),
-                ("view3d.select_circle", dict(deselect=True), dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)),
-            )),
-            ("Select Lasso", None, (
-                ("view3d.select_lasso",
-                 dict(deselect=False), dict(type='EVT_TWEAK_A', value='ANY')),
-                ("view3d.select_lasso",
-                 dict(deselect=True), dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
-            )),
+
+            # 'Select' Group
+            (
+                ("Select Border", None, (
+                    ("view3d.select_border", dict(deselect=False), dict(type='EVT_TWEAK_A', value='ANY')),
+                    ("view3d.select_border", dict(deselect=True), dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
+                )),
+                ("Select Circle", None, (
+                    ("view3d.select_circle", dict(deselect=False), dict(type='ACTIONMOUSE', value='PRESS')),
+                    ("view3d.select_circle", dict(deselect=True), dict(type='ACTIONMOUSE', value='PRESS', ctrl=True)),
+                )),
+                ("Select Lasso", None, (
+                    ("view3d.select_lasso",
+                     dict(deselect=False), dict(type='EVT_TWEAK_A', value='ANY')),
+                    ("view3d.select_lasso",
+                     dict(deselect=True), dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
+                )),
+            ),
+            # End group.
         ],
         'OBJECT': [
             *_tools_transform,
@@ -122,8 +127,22 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
                 ("mesh.polybuild_hover", dict(use_boundary=True), dict(type='MOUSEM

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list