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:
authorCampbell Barton <ideasman42@gmail.com>2017-10-21 08:19:48 +0300
committerCampbell Barton <ideasman42@gmail.com>2017-10-21 08:39:35 +0300
commite1e7b6db2e01d8ea2219d410200a8856d4597222 (patch)
tree521b1c81d53cc05c923e10f9ad8a3bb1887e899d
parentb66728d63deee0fc9ef517405466d1139871251d (diff)
WM: Initial Tool System
The tool-system it's self is primitive and may be changed. Adding to 2.8 to develop operators and manipulators as tools. Currently this is exposed in the toolbar, collapsed by default. Work-flow remains unchanged if you don't change the active tool. Placing the 3D cursor is now a Click instead of a Press event, this allows tweak events to be mapped to tools such as border select, keeping click for 3D cursor placement when selection tools are set.
-rw-r--r--release/scripts/startup/bl_ui/__init__.py6
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py127
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py134
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c2
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h13
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c10
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c35
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c58
8 files changed, 383 insertions, 2 deletions
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index d7135ca202c..a12fd6352ea 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -64,6 +64,12 @@ _modules = [
"properties_scene",
"properties_texture",
"properties_world",
+
+ # Generic Space Modules
+ #
+ # Depends on DNA_WORKSPACE_TOOL (C define).
+ "space_toolsystem_toolbar",
+
"space_clip",
"space_console",
"space_dopesheet",
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..38971f73984
--- /dev/null
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -0,0 +1,127 @@
+# ##### 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
+
+__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)``
+ """
+
+ @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.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 = {}
+
+ for t in cls.tools_all():
+ text, mp_idname, actions = t
+ 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
+ km_idname_active = workspace.tool_keymap or None
+ mp_idname_active = workspace.tool_manipulator_group or None
+ layout = self.layout
+
+ for tool_items in self.tools_from_context(context):
+ if tool_items:
+ col = layout.box().column()
+ for item in tool_items:
+ if item is None:
+ col = layout.box().column()
+ continue
+ text, mp_idname, actions = item
+
+ if actions is not None:
+ km, km_idname = self._tool_keymap[text]
+ else:
+ km = None
+ km_idname = None
+
+ props = col.operator(
+ "wm.tool_set",
+ text=text,
+ emboss=(
+ km_idname_active == km_idname and
+ mp_idname_active == mp_idname
+ ),
+ )
+
+ props.keymap = km_idname or ""
+ props.manipulator_group = mp_idname or ""
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
new file mode 100644
index 00000000000..d8843d4fbce
--- /dev/null
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -0,0 +1,134 @@
+# ##### 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>
+
+# For now group all tools together
+# we may want to move these into per space-type files.
+#
+# For now keep this in a single file since it's an area that may change,
+# so avoid making changes all over the place.
+
+from bpy.types import Panel
+
+from .space_toolsystem_common import (
+ ToolSelectPanelHelper,
+)
+
+
+class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'TOOLS'
+ bl_category = "Tools"
+ bl_label = "Active Tool (Test)"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ # Satisfy the 'ToolSelectPanelHelper' API.
+ keymap_prefix = "3D View Tool: "
+
+ @classmethod
+ def tools_from_context(cls, context):
+ return (cls._tools[None], cls._tools.get(context.mode, ()))
+
+ @classmethod
+ def tools_all(cls):
+ return [t for t_list in cls._tools.values() for t in t_list if t is not None]
+
+ # Internal Data
+
+ # for reuse
+ _tools_transform = (
+ ("Translate", None,
+ (("transform.translate", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')),)),
+ ("Rotate", None,
+ (("transform.rotate", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')),)),
+ ("Scale", None,
+ (("transform.resize", dict(release_confirm=True), dict(type='EVT_TWEAK_A', value='ANY')),)),
+ )
+
+ _tools = {
+ 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)),
+ )),
+ ],
+ 'OBJECT': [
+ *_tools_transform,
+ ],
+ 'POSE': [
+ *_tools_transform,
+ ],
+ 'EDIT_ARMATURE': [
+ *_tools_transform,
+ ("Roll", None, (
+ ("transform.transform",
+ dict(release_confirm=True, mode='BONE_ROLL'),
+ dict(type='EVT_TWEAK_A', value='ANY')),
+ )),
+ None,
+ ("Extrude Cursor", None,
+ (("armature.click_extrude", dict(), dict(type='ACTIONMOUSE', value='PRESS')),)),
+ ],
+ 'EDIT_MESH': [
+ *_tools_transform,
+ None,
+ ("Rip Region", None, (
+ ("mesh.rip_move", dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ )),
+ ("Rip Edge", None, (
+ ("mesh.rip_edge_move", dict(TRANSFORM_OT_translate=dict(release_confirm=True)),
+ dict(type='ACTIONMOUSE', value='PRESS')),
+ )),
+ ("Knife", None, (("mesh.knife_tool", dict(wait_for_input=False), dict(type='ACTIONMOUSE', value='PRESS')),)),
+ ("Bisect", None, (("mesh.bisect", dict(), dict(type='EVT_TWEAK_A', value='ANY')),)),
+ ("Extrude Cursor", None,
+ (("mesh.dupli_extrude_cursor", dict(), dict(type='ACTIONMOUSE', value='PRESS')),)),
+ ],
+ 'EDIT_CURVE': [
+ *_tools_transform,
+ None,
+ ("Draw", None,
+ (("curve.draw", dict(wait_for_input=False), dict(type='ACTIONMOUSE', value='PRESS')),)),
+ ("Extrude Cursor", None,
+ (("curve.vertex_add", dict(), dict(type='ACTIONMOUSE', value='PRESS')),)),
+ ],
+ }
+
+
+classes = (
+ VIEW3D_PT_tools_active,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 6f05dd353d7..ddba3c69320 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -238,7 +238,7 @@ void view3d_keymap(wmKeyConfig *keyconf)
/* only for region 3D window */
keymap = WM_keymap_find(keyconf, "3D View", SPACE_VIEW3D, 0);
- WM_keymap_verify_item(keymap, "VIEW3D_OT_cursor3d", ACTIONMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_verify_item(keymap, "VIEW3D_OT_cursor3d", ACTIONMOUSE, KM_CLICK, 0, 0);
WM_keymap_verify_item(keymap, "VIEW3D_OT_rotate", MIDDLEMOUSE, KM_PRESS, 0, 0);
WM_keymap_verify_item(keymap, "VIEW3D_OT_move", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0);
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index 272d0cd110a..172903fe312 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -50,6 +50,16 @@
# endif
#endif
+/* Currently testing, allow to disable. */
+#define USE_WORKSPACE_TOOL
+
+typedef struct bToolDef {
+ /* either the keymap AND/OR manipulator_group must be defined. */
+ char keymap[64];
+ char manipulator_group[64];
+ int spacetype;
+ int _pad;
+} bToolDef;
/**
* \brief Wrapper for bScreen.
@@ -80,6 +90,9 @@ typedef struct WorkSpace {
int object_mode DNA_PRIVATE_WORKSPACE; /* enum eObjectMode */
int flags DNA_PRIVATE_WORKSPACE; /* enum eWorkSpaceFlags */
+ /* should be: '#ifdef USE_WORKSPACE_TOOL'. */
+ bToolDef tool;
+
struct SceneLayer *render_layer DNA_PRIVATE_WORKSPACE;
char engine_id[32]; /* Render Engine. */
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
index 4e04581a0a8..8cf5e3e8eaf 100644
--- a/source/blender/makesrna/intern/rna_workspace.c
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -146,6 +146,16 @@ static void rna_def_workspace(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mode", "Object interaction mode");
#endif
+ prop = RNA_def_property(srna, "tool_keymap", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "tool.keymap");
+ RNA_def_property_ui_text(prop, "Active Tool", "Currently active tool keymap");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "tool_manipulator_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "tool.manipulator_group");
+ RNA_def_property_ui_text(prop, "Active Tool", "Currently active tool manipulator");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop = RNA_def_property(srna, "orientations", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "transform_orientations", NULL);
RNA_def_property_struct_type(prop, "TransformOrientation");
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 2852b1b4d24..5f69f928eb5 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -2722,9 +2722,42 @@ void wm_event_do_handlers(bContext *C)
wm_drags_check_ops(C, event);
}
}
-
+
+#ifdef USE_WORKSPACE_TOOL
+ /* How to solve properly?
+ *
+ * Handlers are stored in each region,
+ * however the tool-system swaps keymaps often and isn't stored
+ * per region.
+ *
+ * Need to investigate how this could be done better.
+ * We might need to add a more dynamic handler type that uses a callback
+ * to fetch its current keymap.
+ */
+ wmEventHandler sneaky_handler = {NULL};
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ if (workspace->tool.keymap[0] &&
+ workspace->tool.spacetype == sa->spacetype)
+ {
+ wmKeyMap *km = WM_keymap_find_all(
+ C, workspace->tool.keymap, sa->spacetype, RGN_TYPE_WINDOW);
+ if (km != NULL) {
+ sneaky_handler.keymap = km;
+ BLI_addhead(&ar->handlers, &sneaky_handler);
+ }
+ }
+ }
+#endif /* USE_WORKSPACE_TOOL */
+
action |= wm_handlers_do(C, event, &ar->handlers);
+#ifdef USE_WORKSPACE_TOOL
+ if (sneaky_handler.keymap) {
+ BLI_remlink(&ar->handlers, &sneaky_handler);
+ }
+#endif /* USE_WORKSPACE_TOOL */
+
/* fileread case (python), [#29489] */
if (CTX_wm_window(C) == NULL)
return;
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 970b6ebf51d..a5c4228cd2e 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -52,6 +52,7 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "BLT_translation.h"
@@ -1743,6 +1744,60 @@ static void WM_OT_operator_defaults(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
}
+#ifdef USE_WORKSPACE_TOOL
+/* ***************** Set Active Tool ************************* */
+
+/* Developers note: in it's current form this doesn't need to be an operator,
+ * keep this as-is for now since it may end up setting an active key-map.
+ */
+
+static int wm_operator_tool_set_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ScrArea *sa = CTX_wm_area(C);
+ char id_keymap[sizeof(workspace->tool.keymap)];
+ char id_manipulator_group[sizeof(workspace->tool.manipulator_group)];
+ RNA_string_get(op->ptr, "keymap", id_keymap);
+ RNA_string_get(op->ptr, "manipulator_group", id_manipulator_group);
+
+ if (workspace->tool.manipulator_group[0]) {
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(workspace->tool.manipulator_group, false);
+ if (wgt != NULL) {
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params);
+ WM_manipulatormaptype_group_unlink(C, bmain, mmap_type, wgt);
+ }
+ }
+
+ /* NOTE: we may want to move this logic into a function. */
+ {
+ BLI_strncpy(workspace->tool.keymap, id_keymap, sizeof(workspace->tool.keymap));
+ BLI_strncpy(workspace->tool.manipulator_group, id_manipulator_group, sizeof(workspace->tool.manipulator_group));
+ workspace->tool.spacetype = sa->spacetype;
+ }
+
+ if (workspace->tool.manipulator_group[0]) {
+ WM_manipulator_group_type_ensure(workspace->tool.manipulator_group);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void WM_OT_tool_set(wmOperatorType *ot)
+{
+ ot->name = "Set Active Tool";
+ ot->idname = "WM_OT_tool_set";
+ ot->description = "Set the active tool";
+
+ ot->exec = wm_operator_tool_set_exec;
+
+ ot->flag = OPTYPE_INTERNAL;
+
+ RNA_def_string(ot->srna, "keymap", NULL, KMAP_MAX_NAME, "Key Map", "");
+ RNA_def_string(ot->srna, "manipulator_group", NULL, MAX_NAME, "Manipulator Group", "");
+}
+#endif /* USE_WORKSPACE_TOOL */
+
/* ***************** Splash Screen ************************* */
static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg))
@@ -3604,6 +3659,9 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_memory_statistics);
WM_operatortype_append(WM_OT_debug_menu);
WM_operatortype_append(WM_OT_operator_defaults);
+#ifdef USE_WORKSPACE_TOOL
+ WM_operatortype_append(WM_OT_tool_set);
+#endif
WM_operatortype_append(WM_OT_splash);
WM_operatortype_append(WM_OT_search_menu);
WM_operatortype_append(WM_OT_call_menu);