[Bf-blender-cvs] [5eca16cf8bc] custom-manipulators: Manipulator: templates/examples for Py-API

Campbell Barton noreply at git.blender.org
Mon Jun 26 05:13:33 CEST 2017


Commit: 5eca16cf8bcbca134731e2d79ce6f497f31b8e4a
Author: Campbell Barton
Date:   Sat Jun 24 15:53:35 2017 +1000
Branches: custom-manipulators
https://developer.blender.org/rB5eca16cf8bcbca134731e2d79ce6f497f31b8e4a

Manipulator: templates/examples for Py-API

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

A	doc/python_api/examples/bpy.types.ManipulatorGroup.py
M	doc/python_api/sphinx_doc_gen.py
A	release/scripts/templates_py/manipulator_operator.py
A	release/scripts/templates_py/manipulator_operator_target.py
A	release/scripts/templates_py/manipulator_simple.py

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

diff --git a/doc/python_api/examples/bpy.types.ManipulatorGroup.py b/doc/python_api/examples/bpy.types.ManipulatorGroup.py
new file mode 100644
index 00000000000..fa431bc5a88
--- /dev/null
+++ b/doc/python_api/examples/bpy.types.ManipulatorGroup.py
@@ -0,0 +1,29 @@
+"""
+Manipulator Overview
+--------------------
+
+Manipulators are created using two classes.
+
+- :class:`bpy.types.ManipulatorGroup` - stores a list of manipulators.
+
+  The manipulator group is associated with a space and region type.
+- :class:`bpy.types.Manipulator` - a single item which can be used.
+
+  Each manipulator group has a collection of manipulators which it manages.
+
+The following example shows a manipulator group with a single,
+manipulator used to control a lamp objects energy.
+
+.. literalinclude:: __/__/__/release/scripts/templates_py/manipulator_simple.py
+
+
+It's also possible to use a manipulator to run an operator.
+
+.. literalinclude:: __/__/__/release/scripts/templates_py/manipulator_operator_target.py
+
+This more comprehensive example shows how an operator can create a temporary manipulator group to adjust its settings.
+
+.. literalinclude:: __/__/__/release/scripts/templates_py/manipulator_operator.py
+
+"""
+
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index a6ae89ffd6a..b3aebcf6188 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -332,6 +332,9 @@ except ImportError:
 # to avoid having to match Blender's source tree.
 EXTRA_SOURCE_FILES = (
     "../../../release/scripts/templates_py/bmesh_simple.py",
+    "../../../release/scripts/templates_py/manipulator_operator.py",
+    "../../../release/scripts/templates_py/manipulator_operator_target.py",
+    "../../../release/scripts/templates_py/manipulator_simple.py",
     "../../../release/scripts/templates_py/operator_simple.py",
     "../../../release/scripts/templates_py/ui_panel_simple.py",
     "../../../release/scripts/templates_py/ui_previews_custom_icon.py",
diff --git a/release/scripts/templates_py/manipulator_operator.py b/release/scripts/templates_py/manipulator_operator.py
new file mode 100644
index 00000000000..0ba871bea84
--- /dev/null
+++ b/release/scripts/templates_py/manipulator_operator.py
@@ -0,0 +1,224 @@
+# Example of an operator which uses manipulators to control its properties.
+#
+# Usage: Run this script, then in mesh edit-mode press Spacebar
+# to activate the operator "Select Side of Plane"
+# The manipulators can then be used to adjust the plane in the 3D view.
+#
+import bpy
+import bmesh
+
+from bpy.types import (
+    Operator,
+    ManipulatorGroup,
+)
+
+from bpy.props import (
+    FloatVectorProperty,
+)
+
+def main(context, plane_co, plane_no):
+    obj = context.active_object
+    matrix = obj.matrix_world.copy()
+    me = obj.data
+    bm = bmesh.from_edit_mesh(me)
+
+    plane_dot = plane_no.dot(plane_co)
+
+    for v in bm.verts:
+        co = matrix * v.co
+        v.select = (plane_no.dot(co) > plane_dot)
+    bm.select_flush_mode()
+
+    bmesh.update_edit_mesh(me)
+
+
+class SelectSideOfPlane(Operator):
+    """UV Operator description"""
+    bl_idname = "mesh.select_side_of_plane"
+    bl_label = "Select Side of Plane"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    plane_co = FloatVectorProperty(
+        size=3,
+        default=(0, 0, 0),
+    )
+    plane_no = FloatVectorProperty(
+        size=3,
+        default=(0, 0, 1),
+    )
+
+    @classmethod
+    def poll(cls, context):
+        return (context.mode == 'EDIT_MESH')
+
+    def invoke(self, context, event):
+
+        if not self.properties.is_property_set("plane_co"):
+            self.plane_co = context.scene.cursor_location
+
+        if not self.properties.is_property_set("plane_no"):
+            if context.space_data.type == 'VIEW_3D':
+                rv3d = context.space_data.region_3d
+                view_inv = rv3d.view_matrix.to_3x3()
+                # view y axis
+                self.plane_no = view_inv[1].normalized()
+
+        self.execute(context)
+
+        if context.space_data.type == 'VIEW_3D':
+            wm = context.window_manager
+            wm.manipulator_group_type_add(SelectSideOfPlaneManipulatorGroup.bl_idname)
+
+        return {'FINISHED'}
+
+    def execute(self, context):
+        from mathutils import Vector
+        main(context, Vector(self.plane_co), Vector(self.plane_no))
+        return {'FINISHED'}
+
+
+# Manipulators for plane_co, plane_no
+class SelectSideOfPlaneManipulatorGroup(ManipulatorGroup):
+    bl_idname = "MESH_WGT_select_side_of_plane"
+    bl_label = "Side of Plane Manipulator"
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'WINDOW'
+    bl_options = {'3D'}
+
+    # Helper functions
+    @staticmethod
+    def my_target_operator(context):
+        wm = context.window_manager
+        op = wm.operators[-1] if wm.operators else None
+        if isinstance(op, SelectSideOfPlane):
+            return op
+        return None
+
+    @staticmethod
+    def my_view_orientation(context):
+        rv3d = context.space_data.region_3d
+        view_inv = rv3d.view_matrix.to_3x3()
+        return view_inv.normalized()
+
+    @classmethod
+    def poll(cls, context):
+        op = cls.my_target_operator(context)
+        if op is None:
+            wm = context.window_manager
+            wm.manipulator_group_type_remove(SelectSideOfPlaneManipulatorGroup.bl_idname)
+            return False
+        return True
+
+    def setup(self, context):
+        from mathutils import Matrix, Vector
+
+        # ----
+        # Grab
+
+        def grab_get_cb():
+            op = SelectSideOfPlaneManipulatorGroup.my_target_operator(context)
+            return op.plane_co
+
+        def grab_set_cb(value):
+            op = SelectSideOfPlaneManipulatorGroup.my_target_operator(context)
+            op.plane_co = value
+            # XXX, this may change!
+            op.execute(context)
+
+        mpr = self.manipulators.new("MANIPULATOR_WT_grab_3d")
+        mpr.target_set_handler("offset", get=grab_get_cb, set=grab_set_cb)
+
+        mpr.use_draw_value = True
+
+        mpr.color = 0.8, 0.8, 0.8, 0.5
+        mpr.color_highlight = 1.0, 1.0, 1.0, 1.0
+        mpr.scale_basis = 0.2
+
+        self.widget_grab = mpr
+
+        # ----
+        # Dial
+
+        def direction_get_cb():
+            op = SelectSideOfPlaneManipulatorGroup.my_target_operator(context)
+
+            no_a = self.widget_dial.matrix_basis.col[1].xyz
+            no_b = Vector(op.plane_no)
+
+            no_a = (no_a * self.view_inv).xy.normalized()
+            no_b = (no_b * self.view_inv).xy.normalized()
+            return no_a.angle_signed(no_b)
+
+        def direction_set_cb(value):
+            op = SelectSideOfPlaneManipulatorGroup.my_target_operator(context)
+            matrix_rotate = Matrix.Rotation(-value, 3, self.rotate_axis)
+            no = matrix_rotate * self.widget_dial.matrix_basis.col[1].xyz
+            op.plane_no = no
+            op.execute(context)
+
+        mpr = self.manipulators.new("MANIPULATOR_WT_dial_3d")
+        mpr.target_set_handler("offset", get=direction_get_cb, set=direction_set_cb)
+        mpr.draw_options = {'ANGLE_START_Y'}
+
+        mpr.use_draw_value = True
+
+        mpr.color = 0.8, 0.8, 0.8, 0.5
+        mpr.color_highlight = 1.0, 1.0, 1.0, 1.0
+
+        self.widget_dial = mpr
+
+    def draw_prepare(self, context):
+        from mathutils import Vector
+
+        view_inv = self.my_view_orientation(context)
+
+        self.view_inv = view_inv
+        self.rotate_axis = view_inv[2].xyz
+        self.rotate_up = view_inv[1].xyz
+
+        op = self.my_target_operator(context)
+
+        co = Vector(op.plane_co)
+        no = Vector(op.plane_no).normalized()
+
+        # Grab
+        no_z = no
+        no_y = no_z.orthogonal()
+        no_x = no_z.cross(no_y)
+
+        matrix = self.widget_grab.matrix_basis
+        matrix.identity()
+        matrix.col[0].xyz = no_x
+        matrix.col[1].xyz = no_y
+        matrix.col[2].xyz = no_z
+        matrix.col[3].xyz = co
+
+        # Dial
+        no_z = self.rotate_axis
+        no_y = (no - (no.project(no_z))).normalized()
+        no_x = self.rotate_axis.cross(no_y)
+
+        matrix = self.widget_dial.matrix_basis
+        matrix.identity()
+        matrix.col[0].xyz = no_x
+        matrix.col[1].xyz = no_y
+        matrix.col[2].xyz = no_z
+        matrix.col[3].xyz = co
+
+
+classes = (
+    SelectSideOfPlane,
+    SelectSideOfPlaneManipulatorGroup,
+)
+
+def register():
+    for cls in classes:
+        bpy.utils.register_class(cls)
+
+
+def unregister():
+    for cls in reversed(classes):
+        bpy.utils.unregister_class(cls)
+
+if __name__ == "__main__":
+    register()
diff --git a/release/scripts/templates_py/manipulator_operator_target.py b/release/scripts/templates_py/manipulator_operator_target.py
new file mode 100644
index 00000000000..eafe8b1a863
--- /dev/null
+++ b/release/scripts/templates_py/manipulator_operator_target.py
@@ -0,0 +1,45 @@
+# Example of a manipulator that activates an operator
+# using the predefined dial manipulator to change the camera roll.
+#
+# Usage: Run this script and select a camera in the 3D view.
+#
+import bpy
+from bpy.types import (
+    ManipulatorGroup,
+)
+
+class MyCameraWidgetGroup(ManipulatorGroup):
+    bl_idname = "OBJECT_WGT_test_camera"
+    bl_label = "Object Camera Test Widget"
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'WINDOW'
+    bl_options = {'3D', 'PERSISTENT'}
+
+    @classmethod
+    def poll(cls, context):
+        ob = context.object
+        return (ob and ob.type == 'CAMERA')
+
+    def setup(self, context):
+        # Run an operator using the dial manipulator
+        ob = context.object
+        mpr = self.manipulators.new("MANIPULATOR_WT_dial_3d")
+        props = mpr.target_set_operator("transform.rotate")
+        props.constraint_axis = False, False, True
+        props.constraint_orientation = 'LOCAL'
+        props.release_confirm = True
+
+        mpr.matrix_basis = ob.matrix_world.normalized()
+        mpr.line_width = 3
+
+        mpr.color = 0.8, 0.8, 0.8, 0.5
+        mpr.color_highlight = 1.0, 1.0, 1.0, 1.0
+
+     

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list