Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release/scripts/startup/bl_ui/space_toolsystem_common.py')
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py271
1 files changed, 271 insertions, 0 deletions
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
new file mode 100644
index 00000000000..aff9a8d6170
--- /dev/null
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -0,0 +1,271 @@
+# ##### 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
+from bpy.types import (
+ Menu,
+)
+
+__all__ = (
+ "ToolSelectPanelHelper",
+)
+
+
+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():
+ Returns all tools defined.
+ - tools_from_context(context):
+ Returns tools available in this context.
+
+ Each tool is a triplet:
+ ``(tool_name, manipulator_group_idname, keymap_actions)``
+ For a separator in the toolbar, use ``None``.
+
+ Where:
+ ``tool_name``
+ is the name to display in the interface.
+ ``manipulator_group_idname``
+ is an optional manipulator group to activate when the tool is set.
+ ``keymap_actions``
+ 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 item is not None:
+ if ToolSelectPanelHelper._tool_is_group(item):
+ for sub_item in item:
+ if sub_item is not None:
+ yield sub_item
+ else:
+ yield item
+
+ @classmethod
+ def _tool_vars_from_def(cls, item):
+ text, mp_idname, actions = item
+ km, km_idname = (None, None) if actions is None else cls._tool_keymap[text]
+ return (km_idname, mp_idname)
+
+ @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_index,
+ )
+
+ @staticmethod
+ def _tool_vars_from_button_with_index(context):
+ props = context.button_operator
+ return (
+ (props.keymap or None or None, props.manipulator_group or None),
+ props.index,
+ )
+
+ @classmethod
+ def _km_actionmouse_simple(cls, kc, text, actions):
+
+ # 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)
+
+ km_idname = cls.keymap_prefix + text
+ km = kc.keymaps.get(km_idname)
+ if km is not None:
+ return km, km_idname
+ km = kc.keymaps.new(km_idname, space_type=cls.bl_space_type, region_type='WINDOW')
+ for op_idname, op_props_dict, kmi_kwargs in actions:
+ 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)
+ return km, km_idname
+
+ @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
+
+ # {tool_name: (keymap, keymap_idname, manipulator_group_idname), ...}
+ cls._tool_keymap = {}
+
+ # Track which tool-group was last used for non-active groups.
+ # Blender stores the active tool-group index.
+ #
+ # {tool_name_first: index_in_group, ...}
+ cls._tool_group_active = {}
+
+ # ignore in background mode
+ if kc is None:
+ return
+
+ for item in ToolSelectPanelHelper._tools_flatten(cls.tools_all()):
+ text, mp_idname, actions = item
+ if actions is not None:
+ km, km_idname = cls._km_actionmouse_simple(kc, text, actions)
+ cls._tool_keymap[text] = km, km_idname
+
+ def draw(self, context):
+ # 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.
+
+ workspace = context.workspace
+ tool_def_active, index_active = self._tool_vars_from_active_with_index(context)
+ layout = self.layout
+
+ for tool_items in self.tools_from_context(context):
+ if tool_items:
+ col = layout.column(align=True)
+ for item in tool_items:
+ if item is None:
+ col = layout.column(align=True)
+ continue
+
+ if self._tool_is_group(item):
+ is_active = False
+ i = 0
+ for i, sub_item in enumerate(item):
+ if sub_item is None:
+ continue
+ tool_def = self._tool_vars_from_def(sub_item)
+ is_active = (tool_def == tool_def_active)
+ if is_active:
+ index = i
+ break
+ del i, sub_item
+
+ if is_active:
+ # not ideal, write this every time :S
+ self._tool_group_active[item[0][0]] = index
+ else:
+ index = self._tool_group_active.get(item[0][0], 0)
+
+ item = item[index]
+ use_menu = True
+ else:
+ index = -1
+ use_menu = False
+
+ tool_def = self._tool_vars_from_def(item)
+ is_active = (tool_def == tool_def_active)
+
+ if use_menu:
+ props = col.operator_menu_hold(
+ "wm.tool_set",
+ text=item[0],
+ depress=is_active,
+ menu="WM_MT_toolsystem_submenu",
+ )
+ else:
+ props = col.operator(
+ "wm.tool_set",
+ text=item[0],
+ depress=is_active,
+ )
+
+ props.keymap = tool_def[0] or ""
+ props.manipulator_group = tool_def[1] 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:
+ tool_def_button, index_button = cls._tool_vars_from_button_with_index(context)
+
+ 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]
+ tool_def = cls._tool_vars_from_def(item)
+ is_active = (tool_def == tool_def_button)
+ 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("Unable to find toolbar group")
+ return
+
+ index = 0
+ for item in item_group:
+ if item is None:
+ layout.separator()
+ continue
+ tool_def = cls._tool_vars_from_def(item)
+ props = layout.operator(
+ "wm.tool_set",
+ text=item[0],
+ )
+ props.keymap = tool_def[0] or ""
+ props.manipulator_group = tool_def[1] 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)