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:
-rw-r--r--build_files/cmake/macros.cmake2
-rw-r--r--doc/python_api/examples/bpy.types.ManipulatorGroup.py29
-rw-r--r--doc/python_api/sphinx_doc_gen.py3
-rw-r--r--release/scripts/modules/bpy_types.py29
-rw-r--r--release/scripts/templates_py/manipulator_operator.py224
-rw-r--r--release/scripts/templates_py/manipulator_operator_target.py45
-rw-r--r--release/scripts/templates_py/manipulator_simple.py42
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt1
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c45
-rw-r--r--source/blender/makesrna/intern/rna_wm_manipulator.c1007
-rw-r--r--source/blender/makesrna/intern/rna_wm_manipulator_api.c254
-rw-r--r--source/blender/python/intern/CMakeLists.txt4
-rw-r--r--source/blender/python/intern/bpy.c3
-rw-r--r--source/blender/python/intern/bpy_intern_string.c4
-rw-r--r--source/blender/python/intern/bpy_intern_string.h1
-rw-r--r--source/blender/python/intern/bpy_manipulator_wrap.c231
-rw-r--r--source/blender/python/intern/bpy_manipulator_wrap.h36
-rw-r--r--source/blender/python/intern/bpy_rna.c34
-rw-r--r--source/blender/python/intern/bpy_rna_manipulator.c341
-rw-r--r--source/blender/python/intern/bpy_rna_manipulator.h32
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c28
22 files changed, 2381 insertions, 16 deletions
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 563e83fd79a..836fd5f1a6b 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -612,6 +612,8 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_physics
bf_nodes
bf_rna
+ bf_editor_manipulator_library # rna -> manipulator bad-level calls
+ bf_python
bf_imbuf
bf_blenlib
bf_depsgraph
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/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index 600b29a6b2b..89d8e0746a6 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -592,6 +592,35 @@ class OrderedMeta(RNAMeta):
return OrderedDictMini() # collections.OrderedDict()
+# Same as 'Operator'
+# only without 'as_keywords'
+class Manipulator(StructRNA, metaclass=OrderedMeta):
+ __slots__ = ()
+
+ def __getattribute__(self, attr):
+ properties = StructRNA.path_resolve(self, "properties")
+ bl_rna = getattr(properties, "bl_rna", None)
+ if (bl_rna is not None) and (attr in bl_rna.properties):
+ return getattr(properties, attr)
+ return super().__getattribute__(attr)
+
+ def __setattr__(self, attr, value):
+ properties = StructRNA.path_resolve(self, "properties")
+ bl_rna = getattr(properties, "bl_rna", None)
+ if (bl_rna is not None) and (attr in bl_rna.properties):
+ return setattr(properties, attr, value)
+ return super().__setattr__(attr, value)
+
+ def __delattr__(self, attr):
+ properties = StructRNA.path_resolve(self, "properties")
+ bl_rna = getattr(properties, "bl_rna", None)
+ if (bl_rna is not None) and (attr in bl_rna.properties):
+ return delattr(properties, attr)
+ return super().__delattr__(attr)
+
+ target_set_handler = _bpy._rna_manipulator_target_set_handler
+
+
# Only defined so operators members can be used by accessing self.order
# with doc generation 'self.properties.bl_rna.properties' can fail
class Operator(StructRNA, metaclass=OrderedMeta):
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
+
+ self.roll_widget = mpr
+
+ def refresh(self, context):
+ ob = context.object
+ mpr = self.roll_widget
+ mpr.matrix_basis = ob.matrix_world.normalized()
+
+bpy.utils.register_class(MyCameraWidgetGroup)
diff --git a/release/scripts/templates_py/manipulator_simple.py b/release/scripts/templates_py/manipulator_simple.py
new file mode 100644
index 00000000000..6cb232312e8
--- /dev/null
+++ b/release/scripts/templates_py/manipulator_simple.py
@@ -0,0 +1,42 @@
+# Example of a group that edits a single property
+# using the predefined manipulator arrow.
+#
+# Usage: Select a lamp in the 3D view and drag the arrow at it's rear
+# to change it's energy value.
+#
+import bpy
+from bpy.types import (
+ ManipulatorGroup,
+)
+
+class MyLampWidgetGroup(ManipulatorGroup):
+ bl_idname = "OBJECT_WGT_lamp_test"
+ bl_label = "Test Lamp 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 == 'LAMP')
+
+ def setup(self, context):
+ # Arrow manipulator has one 'offset' property we can assign to the lamp energy.
+ ob = context.object
+ mpr = self.manipulators.new("MANIPULATOR_WT_arrow_3d")
+ mpr.target_set_prop("offset", ob.data, "energy")
+ mpr.matrix_basis = ob.matrix_world.normalized()
+ mpr.draw_style = 'BOX'
+
+ mpr.color = 1, 0.5, 0, 0.5
+ mpr.color_highlight = 1, 0.5, 1, 0.5
+
+ self.energy_widget = mpr
+
+ def refresh(self, context):
+ ob = context.object
+ mpr = self.energy_widget
+ mpr.matrix_basis = ob.matrix_world.normalized()
+
+bpy.utils.register_class(MyLampWidgetGroup)
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index d57fbbbd764..75d127079b9 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -127,6 +127,7 @@ set(APISRC
rna_ui_api.c
rna_vfont_api.c
rna_wm_api.c
+ rna_wm_manipulator_api.c
)
string(REGEX REPLACE "rna_([a-zA-Z0-9_-]*).c" "${CMAKE_CURRENT_BINARY_DIR}/rna_\\1_gen.c" GENSRC "${DEFSRC}")
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 20b3daeb79d..7d2ce4cb3b2 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3365,7 +3365,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_userdef.c", NULL, RNA_def_userdef},
{"rna_vfont.c", "rna_vfont_api.c", RNA_def_vfont},
{"rna_wm.c", "rna_wm_api.c", RNA_def_wm},
- {"rna_wm_manipulator.c", NULL, RNA_def_wm_manipulator},
+ {"rna_wm_manipulator.c", "rna_wm_manipulator_api.c", RNA_def_wm_manipulator},
{"rna_workspace.c", NULL, RNA_def_workspace},
{"rna_world.c", NULL, RNA_def_world},
{"rna_movieclip.c", NULL, RNA_def_movieclip},
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 677ea92aea1..166b6f96956 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -71,6 +71,8 @@ EnumPropertyItem rna_enum_window_cursor_items[] = {
#include "UI_interface.h"
#include "BKE_context.h"
+#include "WM_types.h"
+
static wmKeyMap *rna_keymap_active(wmKeyMap *km, bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -115,6 +117,37 @@ static void rna_event_timer_remove(struct wmWindowManager *wm, wmTimer *timer)
WM_event_remove_timer(wm, timer->win, timer);
}
+
+static wmManipulatorGroupType *wm_manipulatorgrouptype_find_for_add_remove(ReportList *reports, const char *idname)
+{
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, true);
+ if (wgt == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Manipulator group type '%s' not found!", idname);
+ return NULL;
+ }
+ if (wgt->flag & WM_MANIPULATORGROUPTYPE_PERSISTENT) {
+ BKE_reportf(reports, RPT_ERROR, "Manipulator group '%s' has 'PERSISTENT' option set!", idname);
+ return NULL;
+ }
+ return wgt;
+}
+
+static void rna_manipulator_group_type_add(ReportList *reports, const char *idname)
+{
+ wmManipulatorGroupType *wgt = wm_manipulatorgrouptype_find_for_add_remove(reports, idname);
+ if (wgt != NULL) {
+ WM_manipulator_group_add_ptr(wgt);
+ }
+}
+
+static void rna_manipulator_group_type_remove(Main *bmain, ReportList *reports, const char *idname)
+{
+ wmManipulatorGroupType *wgt = wm_manipulatorgrouptype_find_for_add_remove(reports, idname);
+ if (wgt != NULL) {
+ WM_manipulator_group_remove_ptr(bmain, wgt);
+ }
+}
+
/* placeholder data for final implementation of a true progressbar */
static struct wmStaticProgress {
float min;
@@ -426,6 +459,18 @@ void RNA_api_wm(StructRNA *srna)
parm = RNA_def_pointer(func, "timer", "Timer", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ func = RNA_def_function(srna, "manipulator_group_type_add", "rna_manipulator_group_type_add");
+ RNA_def_function_ui_description(func, "Activate an existing widget group (when the persistent option isn't set)");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "identifier", NULL, 0, "", "Manipulator group type name");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "manipulator_group_type_remove", "rna_manipulator_group_type_remove");
+ RNA_def_function_ui_description(func, "De-activate a widget group (when the persistent option isn't set)");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_MAIN | FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "identifier", NULL, 0, "", "Manipulator group type name");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
/* Progress bar interface */
func = RNA_def_function(srna, "progress_begin", "rna_progress_begin");
RNA_def_function_ui_description(func, "Start progress report");
diff --git a/source/blender/makesrna/intern/rna_wm_manipulator.c b/source/blender/makesrna/intern/rna_wm_manipulator.c
index 06e31688a8a..030f1a1628c 100644
--- a/source/blender/makesrna/intern/rna_wm_manipulator.c
+++ b/source/blender/makesrna/intern/rna_wm_manipulator.c
@@ -63,6 +63,7 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_workspace.h"
+#include "BKE_utildefines.h"
#include "MEM_guardedalloc.h"
@@ -75,6 +76,171 @@
/** \name Manipulator API
* \{ */
+static void rna_manipulator_draw_cb(
+ const struct bContext *C, struct wmManipulator *mpr)
+{
+ extern FunctionRNA rna_Manipulator_draw_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "draw"); */
+ func = &rna_Manipulator_draw_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_manipulator_draw_select_cb(
+ const struct bContext *C, struct wmManipulator *mpr, int select_id)
+{
+ extern FunctionRNA rna_Manipulator_draw_select_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "draw_select"); */
+ func = &rna_Manipulator_draw_select_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "select_id", &select_id);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static int rna_manipulator_test_select_cb(
+ struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event)
+{
+ extern FunctionRNA rna_Manipulator_test_select_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "test_select"); */
+ func = &rna_Manipulator_test_select_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "event", &event);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+
+ void *ret;
+ RNA_parameter_get_lookup(&list, "intersect_id", &ret);
+ int intersect_id = *(int *)ret;
+
+ RNA_parameter_list_free(&list);
+ return intersect_id;
+}
+
+static void rna_manipulator_modal_cb(
+ struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event, int tweak)
+{
+ extern FunctionRNA rna_Manipulator_modal_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "modal"); */
+ func = &rna_Manipulator_modal_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "event", &event);
+ RNA_parameter_set_lookup(&list, "tweak", &tweak);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_manipulator_setup_cb(
+ struct wmManipulator *mpr)
+{
+ extern FunctionRNA rna_Manipulator_setup_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "setup"); */
+ func = &rna_Manipulator_setup_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ mgroup->type->ext.call((bContext *)NULL, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+
+static void rna_manipulator_invoke_cb(
+ struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event)
+{
+ extern FunctionRNA rna_Manipulator_invoke_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "invoke"); */
+ func = &rna_Manipulator_invoke_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "event", &event);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_manipulator_exit_cb(
+ struct bContext *C, struct wmManipulator *mpr, bool cancel)
+{
+ extern FunctionRNA rna_Manipulator_exit_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "exit"); */
+ func = &rna_Manipulator_exit_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ {
+ int cancel_i = cancel;
+ RNA_parameter_set_lookup(&list, "cancel", &cancel_i);
+ }
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_manipulator_select_cb(
+ struct bContext *C, struct wmManipulator *mpr, int action)
+{
+ extern FunctionRNA rna_Manipulator_select_func;
+ wmManipulatorGroup *mgroup = mpr->parent_mgroup;
+ PointerRNA mpr_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr);
+ /* RNA_struct_find_function(&mpr_ptr, "select"); */
+ func = &rna_Manipulator_select_func;
+ RNA_parameter_list_create(&list, &mpr_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ RNA_parameter_set_lookup(&list, "action", &action);
+ mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list);
+ RNA_parameter_list_free(&list);
+}
+
+/* just to work around 'const char *' warning and to ensure this is a python op */
+static void rna_Manipulator_bl_idname_set(PointerRNA *ptr, const char *value)
+{
+ wmManipulator *data = ptr->data;
+ char *str = (char *)data->type->idname;
+ if (!str[0]) {
+ BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */
+ }
+ else {
+ assert(!"setting the bl_idname on a non-builtin operator");
+ }
+}
+
static wmManipulator *rna_ManipulatorProperties_find_operator(PointerRNA *ptr)
{
#if 0
@@ -83,7 +249,7 @@ static wmManipulator *rna_ManipulatorProperties_find_operator(PointerRNA *ptr)
/* We could try workaruond this lookup, but not trivial. */
for (bScreen *screen = G.main->screen.first; screen; screen = screen->id.next) {
- IDProperty *properties = (IDProperty *)ptr->data;
+ IDProperty *properties = ptr->data;
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->manipulator_map) {
@@ -127,10 +293,202 @@ static IDProperty *rna_ManipulatorProperties_idprops(PointerRNA *ptr, bool creat
static PointerRNA rna_Manipulator_properties_get(PointerRNA *ptr)
{
- wmManipulator *mpr = (wmManipulator *)ptr->data;
+ wmManipulator *mpr = ptr->data;
return rna_pointer_inherit_refine(ptr, mpr->type->srna, mpr->properties);
}
+/* wmManipulator.float */
+#define RNA_MANIPULATOR_GENERIC_FLOAT_RW_DEF(func_id, member_id) \
+static float rna_Manipulator_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ return mpr->member_id; \
+} \
+static void rna_Manipulator_##func_id##_set(PointerRNA *ptr, float value) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ mpr->member_id = value; \
+}
+/* wmManipulator.float[len] */
+#define RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(func_id, member_id, len) \
+static void rna_Manipulator_##func_id##_get(PointerRNA *ptr, float value[len]) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ memcpy(value, mpr->member_id, sizeof(float[len])); \
+} \
+static void rna_Manipulator_##func_id##_set(PointerRNA *ptr, const float value[len]) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ memcpy(mpr->member_id, value, sizeof(float[len])); \
+}
+
+/* wmManipulator.flag */
+#define RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(func_id, member_id, flag_value) \
+static int rna_Manipulator_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ return (mpr->member_id & flag_value) != 0; \
+} \
+static void rna_Manipulator_##func_id##_set(PointerRNA *ptr, int value) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ BKE_BIT_TEST_SET(mpr->member_id, value, flag_value); \
+}
+
+#define RNA_MANIPULATOR_FLAG_RO_DEF(func_id, member_id, flag_value) \
+static int rna_Manipulator_##func_id##_get(PointerRNA *ptr) \
+{ \
+ wmManipulator *mpr = ptr->data; \
+ return (mpr->member_id & flag_value) != 0; \
+}
+
+RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(color, color, 4);
+RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(color_hi, color_hi, 4);
+
+RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(matrix_basis, matrix_basis, 16);
+RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(matrix_offset, matrix_offset, 16);
+
+RNA_MANIPULATOR_GENERIC_FLOAT_RW_DEF(scale_basis, scale_basis);
+RNA_MANIPULATOR_GENERIC_FLOAT_RW_DEF(line_width, line_width);
+
+RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_hover, flag, WM_MANIPULATOR_DRAW_HOVER);
+RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_active, flag, WM_MANIPULATOR_DRAW_ACTIVE);
+RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_value, flag, WM_MANIPULATOR_DRAW_VALUE);
+RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_hide, flag, WM_MANIPULATOR_HIDDEN);
+
+/* wmManipulator.state */
+RNA_MANIPULATOR_FLAG_RO_DEF(state_is_highlight, state, WM_MANIPULATOR_STATE_HIGHLIGHT);
+RNA_MANIPULATOR_FLAG_RO_DEF(state_is_active, state, WM_MANIPULATOR_STATE_ACTIVE);
+RNA_MANIPULATOR_FLAG_RO_DEF(state_select, state, WM_MANIPULATOR_STATE_SELECT);
+
+static void rna_Manipulator_name_get(PointerRNA *ptr, char *value)
+{
+ wmManipulator *mpr = ptr->data;
+ strcpy(value, mpr->name);
+}
+
+static void rna_Manipulator_name_set(PointerRNA *ptr, const char *value)
+{
+ wmManipulator *mpr = ptr->data;
+ WM_manipulator_name_set(mpr->parent_mgroup, mpr, value);
+}
+
+static int rna_Manipulator_name_length(PointerRNA *ptr)
+{
+ wmManipulator *mpr = ptr->data;
+ return strlen(mpr->name);
+}
+
+#ifdef WITH_PYTHON
+
+static void rna_Manipulator_unregister(struct Main *bmain, StructRNA *type);
+void BPY_RNA_manipulator_wrapper(wmManipulatorType *wgt, void *userdata);
+
+static StructRNA *rna_Manipulator_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+{
+ struct {
+ char idname[MAX_NAME];
+ } temp_buffers;
+
+ wmManipulatorType dummywt = {NULL};
+ wmManipulator dummymnp = {NULL};
+ PointerRNA mnp_ptr;
+
+ /* Two sets of functions. */
+ int have_function[8];
+
+ /* setup dummy manipulator & manipulator type to store static properties in */
+ dummymnp.type = &dummywt;
+ dummywt.idname = temp_buffers.idname;
+ RNA_pointer_create(NULL, &RNA_Manipulator, &dummymnp, &mnp_ptr);
+
+ /* Clear so we can detect if it's left unset. */
+ temp_buffers.idname[0] = '\0';
+
+ /* validate the python class */
+ if (validate(&mnp_ptr, data, have_function) != 0)
+ return NULL;
+
+ if (strlen(identifier) >= sizeof(temp_buffers.idname)) {
+ BKE_reportf(reports, RPT_ERROR, "Registering manipulator class: '%s' is too long, maximum length is %d",
+ identifier, (int)sizeof(temp_buffers.idname));
+ return NULL;
+ }
+
+ /* check if we have registered this manipulator type before, and remove it */
+ {
+ const wmManipulatorType *wt = WM_manipulatortype_find(dummywt.idname, true);
+ if (wt && wt->ext.srna) {
+ rna_Manipulator_unregister(bmain, wt->ext.srna);
+ }
+ }
+
+ /* create a new manipulator type */
+ dummywt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummywt.idname, &RNA_Manipulator);
+ /* manipulator properties are registered separately */
+ RNA_def_struct_flag(dummywt.ext.srna, STRUCT_NO_IDPROPERTIES);
+ dummywt.ext.data = data;
+ dummywt.ext.call = call;
+ dummywt.ext.free = free;
+
+ {
+ int i = 0;
+ dummywt.draw = (have_function[i++]) ? rna_manipulator_draw_cb : NULL;
+ dummywt.draw_select = (have_function[i++]) ? rna_manipulator_draw_select_cb : NULL;
+ dummywt.test_select = (have_function[i++]) ? rna_manipulator_test_select_cb : NULL;
+ dummywt.modal = (have_function[i++]) ? rna_manipulator_modal_cb : NULL;
+// dummywt.property_update = (have_function[i++]) ? rna_manipulator_property_update : NULL;
+// dummywt.position_get = (have_function[i++]) ? rna_manipulator_position_get : NULL;
+ dummywt.setup = (have_function[i++]) ? rna_manipulator_setup_cb : NULL;
+ dummywt.invoke = (have_function[i++]) ? rna_manipulator_invoke_cb : NULL;
+ dummywt.exit = (have_function[i++]) ? rna_manipulator_exit_cb : NULL;
+ dummywt.select = (have_function[i++]) ? rna_manipulator_select_cb : NULL;
+
+ BLI_assert(i == ARRAY_SIZE(have_function));
+ }
+
+ RNA_def_struct_duplicate_pointers(dummywt.ext.srna);
+
+ /* use duplicated string */
+ dummywt.idname = dummywt.ext.srna->identifier;
+
+ WM_manipulatortype_append_ptr(BPY_RNA_manipulator_wrapper, (void *)&dummywt);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ return dummywt.ext.srna;
+}
+
+static void rna_Manipulator_unregister(struct Main *UNUSED(bmain), StructRNA *type)
+{
+ wmManipulatorType *wt = RNA_struct_blender_type_get(type);
+
+ /* TODO, remove widgets from interface! */
+
+ if (!wt)
+ return;
+
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ RNA_struct_free_extension(type, &wt->ext);
+
+ WM_manipulatortype_remove_ptr(wt);
+
+ RNA_struct_free(&BLENDER_RNA, type);
+}
+
+static void **rna_Manipulator_instance(PointerRNA *ptr)
+{
+ wmManipulator *mpr = ptr->data;
+ return &mpr->py_instance;
+}
+
+#endif /* WITH_PYTHON */
+
+
static StructRNA *rna_Manipulator_refine(PointerRNA *mnp_ptr)
{
wmManipulator *mpr = mnp_ptr->data;
@@ -142,6 +500,296 @@ static StructRNA *rna_Manipulator_refine(PointerRNA *mnp_ptr)
/** \name Manipulator Group API
* \{ */
+static wmManipulator *rna_ManipulatorGroup_manipulator_new(
+ wmManipulatorGroup *mgroup, ReportList *reports, const char *idname, const char *name)
+{
+ const wmManipulatorType *wt = WM_manipulatortype_find(idname, true);
+ if (wt == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "ManipulatorType '%s' not known", idname);
+ return NULL;
+ }
+ wmManipulator *mpr = WM_manipulator_new_ptr(wt, mgroup, name, NULL);
+ return mpr;
+}
+
+static void rna_ManipulatorGroup_manipulator_remove(
+ wmManipulatorGroup *mgroup, bContext *C, wmManipulator *mpr)
+{
+ WM_manipulator_free(&mgroup->manipulators, mgroup->parent_mmap, mpr, C);
+}
+
+static void rna_ManipulatorGroup_manipulator_clear(
+ wmManipulatorGroup *mgroup, bContext *C)
+{
+ while (mgroup->manipulators.first) {
+ WM_manipulator_free(&mgroup->manipulators, mgroup->parent_mmap, mgroup->manipulators.first, C);
+ }
+}
+
+static void rna_ManipulatorGroup_name_get(PointerRNA *ptr, char *value)
+{
+ wmManipulatorGroup *mgroup = ptr->data;
+ strcpy(value, mgroup->type->name);
+}
+
+static int rna_ManipulatorGroup_name_length(PointerRNA *ptr)
+{
+ wmManipulatorGroup *mgroup = ptr->data;
+ return strlen(mgroup->type->name);
+}
+
+/* just to work around 'const char *' warning and to ensure this is a python op */
+static void rna_ManipulatorGroup_bl_idname_set(PointerRNA *ptr, const char *value)
+{
+ wmManipulatorGroup *data = ptr->data;
+ char *str = (char *)data->type->idname;
+ if (!str[0])
+ BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */
+ else
+ assert(!"setting the bl_idname on a non-builtin operator");
+}
+
+static void rna_ManipulatorGroup_bl_label_set(PointerRNA *ptr, const char *value)
+{
+ wmManipulatorGroup *data = ptr->data;
+ char *str = (char *)data->type->name;
+ if (!str[0])
+ BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */
+ else
+ assert(!"setting the bl_label on a non-builtin operator");
+}
+
+static int rna_ManipulatorGroup_has_reports_get(PointerRNA *ptr)
+{
+ wmManipulatorGroup *mgroup = ptr->data;
+ return (mgroup->reports && mgroup->reports->list.first);
+}
+
+#ifdef WITH_PYTHON
+
+static bool rna_manipulatorgroup_poll_cb(const bContext *C, wmManipulatorGroupType *wgt)
+{
+
+ extern FunctionRNA rna_ManipulatorGroup_poll_func;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ void *ret;
+ int visible;
+
+ RNA_pointer_create(NULL, wgt->ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_ManipulatorGroup_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ wgt->ext.call((bContext *)C, &ptr, func, &list);
+
+ RNA_parameter_get_lookup(&list, "visible", &ret);
+ visible = *(int *)ret;
+
+ RNA_parameter_list_free(&list);
+
+ return visible;
+}
+
+static void rna_manipulatorgroup_setup_cb(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ extern FunctionRNA rna_ManipulatorGroup_setup_func;
+
+ PointerRNA mgroup_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, mgroup->type->ext.srna, mgroup, &mgroup_ptr);
+ func = &rna_ManipulatorGroup_setup_func; /* RNA_struct_find_function(&wgroupr, "setup"); */
+
+ RNA_parameter_list_create(&list, &mgroup_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ mgroup->type->ext.call((bContext *)C, &mgroup_ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+static wmKeyMap *rna_manipulatorgroup_setup_keymap_cb(const wmManipulatorGroupType *wgt, wmKeyConfig *config)
+{
+ extern FunctionRNA rna_ManipulatorGroup_setup_keymap_func;
+ const char *wgroupname = wgt->name;
+ void *ret;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, wgt->ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_ManipulatorGroup_setup_keymap_func; /* RNA_struct_find_function(&wgroupr, "setup_keymap"); */
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "keyconfig", &config);
+ RNA_parameter_set_lookup(&list, "manipulator_group", &wgroupname);
+ wgt->ext.call(NULL, &ptr, func, &list);
+
+ RNA_parameter_get_lookup(&list, "keymap", &ret);
+ wmKeyMap *keymap = *(wmKeyMap **)ret;
+
+ RNA_parameter_list_free(&list);
+
+ return keymap;
+}
+
+static void rna_manipulatorgroup_refresh_cb(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ extern FunctionRNA rna_ManipulatorGroup_refresh_func;
+
+ PointerRNA mgroup_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, mgroup->type->ext.srna, mgroup, &mgroup_ptr);
+ func = &rna_ManipulatorGroup_refresh_func; /* RNA_struct_find_function(&wgroupr, "refresh"); */
+
+ RNA_parameter_list_create(&list, &mgroup_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ mgroup->type->ext.call((bContext *)C, &mgroup_ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+static void rna_manipulatorgroup_draw_prepare_cb(const bContext *C, wmManipulatorGroup *mgroup)
+{
+ extern FunctionRNA rna_ManipulatorGroup_draw_prepare_func;
+
+ PointerRNA mgroup_ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create(NULL, mgroup->type->ext.srna, mgroup, &mgroup_ptr);
+ func = &rna_ManipulatorGroup_draw_prepare_func; /* RNA_struct_find_function(&wgroupr, "draw_prepare"); */
+
+ RNA_parameter_list_create(&list, &mgroup_ptr, func);
+ RNA_parameter_set_lookup(&list, "context", &C);
+ mgroup->type->ext.call((bContext *)C, &mgroup_ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
+void BPY_RNA_manipulatorgroup_wrapper(wmManipulatorGroupType *wgt, void *userdata);
+
+static StructRNA *rna_ManipulatorGroup_register(
+ Main *bmain, ReportList *reports, void *data, const char *identifier,
+ StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+{
+ struct {
+ char name[MAX_NAME];
+ char idname[MAX_NAME];
+ } temp_buffers;
+
+ wmManipulatorGroupType dummywgt = {NULL};
+ wmManipulatorGroup dummywg = {NULL};
+ PointerRNA wgptr;
+
+ /* Two sets of functions. */
+ int have_function[5];
+
+ /* setup dummy manipulatorgroup & manipulatorgroup type to store static properties in */
+ dummywg.type = &dummywgt;
+ dummywgt.name = temp_buffers.name;
+ dummywgt.idname = temp_buffers.idname;
+
+ RNA_pointer_create(NULL, &RNA_ManipulatorGroup, &dummywg, &wgptr);
+
+ /* Clear so we can detect if it's left unset. */
+ temp_buffers.idname[0] = temp_buffers.name[0] = '\0';
+
+ /* validate the python class */
+ if (validate(&wgptr, data, have_function) != 0)
+ return NULL;
+
+ if (strlen(identifier) >= sizeof(temp_buffers.idname)) {
+ BKE_reportf(reports, RPT_ERROR, "Registering manipulatorgroup class: '%s' is too long, maximum length is %d",
+ identifier, (int)sizeof(temp_buffers.idname));
+ return NULL;
+ }
+
+ /* check if the area supports widgets */
+ const struct wmManipulatorMapType_Params wmap_params = {
+ .spaceid = dummywgt.mmap_params.spaceid,
+ .regionid = dummywgt.mmap_params.regionid,
+ };
+
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wmap_params);
+ if (mmap_type == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Area type does not support manipulators");
+ return NULL;
+ }
+
+ /* check if we have registered this manipulatorgroup type before, and remove it */
+ {
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(dummywgt.idname, true);
+ if (wgt && wgt->ext.srna) {
+ WM_manipulatormaptype_group_unlink(NULL, bmain, mmap_type, wgt);
+ WM_manipulatorgrouptype_remove_ptr(wgt);
+
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+ }
+ }
+
+ /* create a new manipulatorgroup type */
+ dummywgt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummywgt.idname, &RNA_ManipulatorGroup);
+ RNA_def_struct_flag(dummywgt.ext.srna, STRUCT_NO_IDPROPERTIES); /* manipulatorgroup properties are registered separately */
+ dummywgt.ext.data = data;
+ dummywgt.ext.call = call;
+ dummywgt.ext.free = free;
+
+ /* We used to register widget group types like this, now we do it similar to
+ * operator types. Thus we should be able to do the same as operator types now. */
+ dummywgt.poll = (have_function[0]) ? rna_manipulatorgroup_poll_cb : NULL;
+ dummywgt.setup_keymap = (have_function[1]) ? rna_manipulatorgroup_setup_keymap_cb : NULL;
+ dummywgt.setup = (have_function[2]) ? rna_manipulatorgroup_setup_cb : NULL;
+ dummywgt.refresh = (have_function[3]) ? rna_manipulatorgroup_refresh_cb : NULL;
+ dummywgt.draw_prepare = (have_function[4]) ? rna_manipulatorgroup_draw_prepare_cb : NULL;
+
+ RNA_def_struct_duplicate_pointers(dummywgt.ext.srna);
+ dummywgt.idname = dummywgt.ext.srna->identifier;
+ dummywgt.name = dummywgt.ext.srna->name;
+
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_append_ptr(
+ BPY_RNA_manipulatorgroup_wrapper, (void *)&dummywgt);
+
+ if (wgt->flag & WM_MANIPULATORGROUPTYPE_PERSISTENT) {
+ WM_manipulator_group_add_ptr_ex(wgt, mmap_type);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+ }
+
+ return dummywgt.ext.srna;
+}
+
+static void rna_ManipulatorGroup_unregister(struct Main *bmain, StructRNA *type)
+{
+ wmManipulatorGroupType *wgt = RNA_struct_blender_type_get(type);
+
+ if (!wgt)
+ return;
+
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ RNA_struct_free_extension(type, &wgt->ext);
+
+ WM_manipulator_group_remove_ptr(bmain, wgt);
+
+ RNA_struct_free(&BLENDER_RNA, type);
+}
+
+static void **rna_ManipulatorGroup_instance(PointerRNA *ptr)
+{
+ wmManipulatorGroup *mgroup = ptr->data;
+ return &mgroup->py_instance;
+}
+
+#endif /* WITH_PYTHON */
+
static StructRNA *rna_ManipulatorGroup_refine(PointerRNA *mgroup_ptr)
{
wmManipulatorGroup *mgroup = mgroup_ptr->data;
@@ -165,10 +813,32 @@ static void rna_def_manipulators(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
RNA_def_property_srna(cprop, "Manipulators");
srna = RNA_def_struct(brna, "Manipulators", NULL);
RNA_def_struct_sdna(srna, "wmManipulatorGroup");
RNA_def_struct_ui_text(srna, "Manipulators", "Collection of manipulators");
+
+ func = RNA_def_function(srna, "new", "rna_ManipulatorGroup_manipulator_new");
+ RNA_def_function_ui_description(func, "Add manipulator");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_string(func, "type", "Type", 0, "", "Manipulator identifier"); /* optional */
+ RNA_def_string(func, "name", "Name", 0, "", "Manipulator name"); /* optional */
+ parm = RNA_def_pointer(func, "manipulator", "Manipulator", "", "New manipulator");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_ManipulatorGroup_manipulator_remove");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Delete manipulator");
+ parm = RNA_def_pointer(func, "manipulator", "Manipulator", "", "New manipulator");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "clear", "rna_ManipulatorGroup_manipulator_clear");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Delete all manipulators");
}
@@ -177,18 +847,222 @@ static void rna_def_manipulator(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
RNA_def_property_srna(cprop, "Manipulator");
srna = RNA_def_struct(brna, "Manipulator", NULL);
RNA_def_struct_sdna(srna, "wmManipulator");
RNA_def_struct_ui_text(srna, "Manipulator", "Collection of manipulators");
RNA_def_struct_refine_func(srna, "rna_Manipulator_refine");
+#ifdef WITH_PYTHON
+ RNA_def_struct_register_funcs(
+ srna,
+ "rna_Manipulator_register",
+ "rna_Manipulator_unregister",
+ "rna_Manipulator_instance");
+#endif
+ RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+
prop = RNA_def_property(srna, "properties", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "ManipulatorProperties");
RNA_def_property_ui_text(prop, "Properties", "");
RNA_def_property_pointer_funcs(prop, "rna_Manipulator_properties_get", NULL, NULL, NULL);
+ /* -------------------------------------------------------------------- */
+ /* Registerable Variables */
+
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->idname");
+ RNA_def_property_string_maxlength(prop, MAX_NAME);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Manipulator_bl_idname_set");
+ /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
+ RNA_def_property_flag(prop, PROP_REGISTER);
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+
+ /* wmManipulator.draw */
+ func = RNA_def_function(srna, "draw", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* wmManipulator.draw_select */
+ func = RNA_def_function(srna, "draw_select", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_int(func, "select_id", 0, 0, INT_MAX, "", "", 0, INT_MAX);
+
+ /* wmManipulator.test_select */
+ func = RNA_def_function(srna, "test_select", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "event", "Event", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_int(func, "intersect_id", 0, 0, INT_MAX, "", "", 0, INT_MAX);
+ RNA_def_function_return(func, parm);
+
+ /* wmManipulator.handler */
+ static EnumPropertyItem tweak_actions[] = {
+ {WM_MANIPULATOR_TWEAK_PRECISE, "PRECISE", 0, "Precise", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ func = RNA_def_function(srna, "modal", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "event", "Event", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ /* TODO, shuold be a enum-flag */
+ parm = RNA_def_enum(func, "tweak", tweak_actions, 0, "Tweak", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_property_flag(parm, PROP_ENUM_FLAG);
+
+ /* wmManipulator.property_update */
+ /* TODO */
+
+ /* wmManipulator.setup */
+ func = RNA_def_function(srna, "setup", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+
+ /* wmManipulator.invoke */
+ func = RNA_def_function(srna, "invoke", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "event", "Event", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* wmManipulator.exit */
+ func = RNA_def_function(srna, "exit", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "cancel", 0, "Cancel, otherwise confirm", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ /* wmManipulator.cursor_get */
+ /* TODO */
+
+ /* wmManipulator.select */
+ /* TODO, de-duplicate! */
+ static EnumPropertyItem select_actions[] = {
+ {SEL_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle selection for all elements"},
+ {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"},
+ {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"},
+ {SEL_INVERT, "INVERT", 0, "Invert", "Invert selection of all elements"},
+ {0, NULL, 0, NULL, NULL}
+ };
+ func = RNA_def_function(srna, "select", NULL);
+ RNA_def_function_ui_description(func, "");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_enum(func, "action", select_actions, 0, "Action", "Selection action to execute");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+
+ /* -------------------------------------------------------------------- */
+ /* Instance Variables */
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(
+ prop, "rna_Manipulator_name_get", "rna_Manipulator_name_length", "rna_Manipulator_name_set");
+ RNA_def_property_ui_text(prop, "Name", "");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_float_funcs(prop, "rna_Manipulator_color_get", "rna_Manipulator_color_set", NULL);
+
+ prop = RNA_def_property(srna, "color_highlight", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_float_funcs(prop, "rna_Manipulator_color_hi_get", "rna_Manipulator_color_hi_set", NULL);
+ RNA_def_property_ui_text(prop, "Color", "");
+
+ prop = RNA_def_property(srna, "matrix_basis", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Basis Matrix", "");
+ RNA_def_property_float_funcs(prop, "rna_Manipulator_matrix_basis_get", "rna_Manipulator_matrix_basis_set", NULL);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "matrix_offset", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(prop, "Offset Matrix", "");
+ RNA_def_property_float_funcs(prop, "rna_Manipulator_matrix_offset_get", "rna_Manipulator_matrix_offset_set", NULL);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "scale_basis", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_ui_text(prop, "Scale Basis", "");
+ RNA_def_property_float_funcs(prop, "rna_Manipulator_scale_basis_get", "rna_Manipulator_scale_basis_set", NULL);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ prop = RNA_def_property(srna, "line_width", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_ui_text(prop, "Line Width", "");
+ RNA_def_property_float_funcs(prop, "rna_Manipulator_line_width_get", "rna_Manipulator_line_width_set", NULL);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ /* wmManipulator.flag */
+ /* WM_MANIPULATOR_HIDDEN */
+ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Manipulator_flag_hide_get", "rna_Manipulator_flag_hide_set");
+ RNA_def_property_ui_text(prop, "Hide", "");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_MANIPULATOR_DRAW_HOVER */
+ prop = RNA_def_property(srna, "use_draw_hover", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Manipulator_flag_use_draw_hover_get", "rna_Manipulator_flag_use_draw_hover_set");
+ RNA_def_property_ui_text(prop, "Draw Hover", "");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_MANIPULATOR_DRAW_ACTIVE */
+ prop = RNA_def_property(srna, "use_draw_active", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Manipulator_flag_use_draw_active_get", "rna_Manipulator_flag_use_draw_active_set");
+ RNA_def_property_ui_text(prop, "Draw Active", "Draw while dragging");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+ /* WM_MANIPULATOR_DRAW_VALUE */
+ prop = RNA_def_property(srna, "use_draw_value", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Manipulator_flag_use_draw_value_get", "rna_Manipulator_flag_use_draw_value_set");
+ RNA_def_property_ui_text(prop, "Draw Value", "Show an indicator for the current value while dragging");
+ RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL);
+
+ /* wmManipulator.state (readonly) */
+ /* WM_MANIPULATOR_STATE_HIGHLIGHT */
+ prop = RNA_def_property(srna, "is_highlight", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Manipulator_state_is_highlight_get", NULL);
+ RNA_def_property_ui_text(prop, "Highlight", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ /* WM_MANIPULATOR_STATE_ACTIVE */
+ prop = RNA_def_property(srna, "is_active", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Manipulator_state_is_active_get", NULL);
+ RNA_def_property_ui_text(prop, "Highlight", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ /* WM_MANIPULATOR_STATE_SELECT */
+ prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Manipulator_state_select_get", NULL);
+ RNA_def_property_ui_text(prop, "Select", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ RNA_api_manipulator(srna);
+
srna = RNA_def_struct(brna, "ManipulatorProperties", NULL);
RNA_def_struct_ui_text(srna, "Manipulator Properties", "Input properties of an Manipulator");
RNA_def_struct_refine_func(srna, "rna_ManipulatorProperties_refine");
@@ -201,10 +1075,137 @@ static void rna_def_manipulatorgroup(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
srna = RNA_def_struct(brna, "ManipulatorGroup", NULL);
RNA_def_struct_ui_text(srna, "ManipulatorGroup", "Storage of an operator being executed, or registered after execution");
RNA_def_struct_sdna(srna, "wmManipulatorGroup");
RNA_def_struct_refine_func(srna, "rna_ManipulatorGroup_refine");
+#ifdef WITH_PYTHON
+ RNA_def_struct_register_funcs(
+ srna,
+ "rna_ManipulatorGroup_register",
+ "rna_ManipulatorGroup_unregister",
+ "rna_ManipulatorGroup_instance");
+#endif
+ RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+
+ /* -------------------------------------------------------------------- */
+ /* Registration */
+
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->idname");
+ RNA_def_property_string_maxlength(prop, MAX_NAME);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ManipulatorGroup_bl_idname_set");
+ RNA_def_property_flag(prop, PROP_REGISTER);
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "bl_label", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->name");
+ RNA_def_property_string_maxlength(prop, MAX_NAME); /* else it uses the pointer size! */
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ManipulatorGroup_bl_label_set");
+ /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
+ RNA_def_property_flag(prop, PROP_REGISTER);
+
+ prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type->mmap_params.spaceid");
+ RNA_def_property_enum_items(prop, rna_enum_space_type_items);
+ RNA_def_property_flag(prop, PROP_REGISTER);
+ RNA_def_property_ui_text(prop, "Space type", "The space where the panel is going to be used in");
+
+ prop = RNA_def_property(srna, "bl_region_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type->mmap_params.regionid");
+ RNA_def_property_enum_items(prop, rna_enum_region_type_items);
+ RNA_def_property_flag(prop, PROP_REGISTER);
+ RNA_def_property_ui_text(prop, "Region Type", "The region where the panel is going to be used in");
+
+ /* bl_options */
+ static EnumPropertyItem manipulatorgroup_flag_items[] = {
+ {WM_MANIPULATORGROUPTYPE_3D, "3D", 0, "3D",
+ "Use in 3D viewport"},
+ {WM_MANIPULATORGROUPTYPE_SCALE, "SCALE", 0, "Scale",
+ "Scale to respect zoom (otherwise zoom independent draw size)"},
+ {WM_MANIPULATORGROUPTYPE_DEPTH_3D, "DEPTH_3D", 0, "Depth 3D",
+ "Supports culled depth by other objects in the view"},
+ {WM_MANIPULATORGROUPTYPE_SELECT, "SELECT", 0, "Select",
+ "Supports selection"},
+ {WM_MANIPULATORGROUPTYPE_PERSISTENT, "PERSISTENT", 0, "Persistent",
+ ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type->flag");
+ RNA_def_property_enum_items(prop, manipulatorgroup_flag_items);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
+ RNA_def_property_ui_text(prop, "Options", "Options for this operator type");
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+
+
+ /* Functions */
+
+ /* poll */
+ func = RNA_def_function(srna, "poll", NULL);
+ RNA_def_function_ui_description(func, "Test if the manipulator group can be called or not");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
+ RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", ""));
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* keymap_init */
+ func = RNA_def_function(srna, "setup_keymap", NULL);
+ RNA_def_function_ui_description(
+ func,
+ "Initialize keymaps for this manipulator group, use fallback keymap when not present");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "keyconf", "KeyConfig", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_property(func, "manipulator_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(parm, "Manipulator Group", "Manipulator Group ID");
+ // RNA_def_property_string_default(parm, "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return */
+ parm = RNA_def_pointer(func, "keymap", "KeyMap", "", "");
+ RNA_def_property_flag(parm, PROP_NEVER_NULL);
+ RNA_def_function_return(func, parm);
+
+ /* setup */
+ func = RNA_def_function(srna, "setup", NULL);
+ RNA_def_function_ui_description(func, "Create manipulators function for the manipulator group");
+ RNA_def_function_flag(func, FUNC_REGISTER);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* refresh */
+ func = RNA_def_function(srna, "refresh", NULL);
+ RNA_def_function_ui_description(func, "Refresh data (called on common state changes such as selection)");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ func = RNA_def_function(srna, "draw_prepare", NULL);
+ RNA_def_function_ui_description(func, "Run before each redraw");
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ /* -------------------------------------------------------------------- */
+ /* Instance Variables */
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_string_funcs(prop, "rna_ManipulatorGroup_name_get", "rna_ManipulatorGroup_name_length", NULL);
+ RNA_def_property_ui_text(prop, "Name", "");
+
+ prop = RNA_def_property(srna, "has_reports", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* this is 'virtual' property */
+ RNA_def_property_boolean_funcs(prop, "rna_ManipulatorGroup_has_reports_get", NULL);
+ RNA_def_property_ui_text(prop, "Has Reports",
+ "ManipulatorGroup has a set of reports (warnings and errors) from last execution");
+
RNA_define_verify_sdna(0); /* not in sdna */
@@ -221,6 +1222,8 @@ static void rna_def_manipulatorgroup(BlenderRNA *brna)
rna_def_manipulators(brna, prop);
RNA_define_verify_sdna(1); /* not in sdna */
+
+ RNA_api_manipulatorgroup(srna);
}
void RNA_def_wm_manipulator(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_wm_manipulator_api.c b/source/blender/makesrna/intern/rna_wm_manipulator_api.c
new file mode 100644
index 00000000000..9f011ad7b7d
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_wm_manipulator_api.c
@@ -0,0 +1,254 @@
+/*
+ * ***** 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 *****
+ */
+
+/** \file blender/makesrna/intern/rna_wm_manipulator_api.c
+ * \ingroup RNA
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+
+#include "BKE_report.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "DNA_windowmanager_types.h"
+
+#include "WM_api.h"
+
+#include "rna_internal.h" /* own include */
+
+#ifdef RNA_RUNTIME
+
+#include "UI_interface.h"
+#include "BKE_context.h"
+
+#include "ED_manipulator_library.h"
+
+static void rna_manipulator_draw_preset_box(
+ wmManipulator *mpr, float matrix[16], int select_id)
+{
+ ED_manipulator_draw_preset_box(mpr, (float (*)[4])matrix, select_id);
+}
+
+static void rna_manipulator_draw_preset_arrow(
+ wmManipulator *mpr, float matrix[16], int axis, int select_id)
+{
+ ED_manipulator_draw_preset_arrow(mpr, (float (*)[4])matrix, axis, select_id);
+}
+
+static void rna_manipulator_draw_preset_circle(
+ wmManipulator *mpr, float matrix[16], int axis, int select_id)
+{
+ ED_manipulator_draw_preset_circle(mpr, (float (*)[4])matrix, axis, select_id);
+}
+
+static void rna_manipulator_draw_preset_facemap(
+ wmManipulator *mpr, struct bContext *C, struct Object *ob, int facemap, int select_id)
+{
+ struct Scene *scene = CTX_data_scene(C);
+ ED_manipulator_draw_preset_facemap(mpr, scene, ob, facemap, select_id);
+}
+
+static void rna_manipulator_target_set_prop(
+ wmManipulator *mpr, ReportList *reports, const char *target_propname,
+ PointerRNA *ptr, const char *propname, int index)
+{
+ const wmManipulatorPropertyType *mpr_prop_type =
+ WM_manipulatortype_target_property_find(mpr->type, target_propname);
+ if (mpr_prop_type == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Manipulator target property '%s.%s' not found",
+ mpr->type->idname, target_propname);
+ return;
+ }
+
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+ if (prop == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Property '%s.%s' not found",
+ RNA_struct_identifier(ptr->type), target_propname);
+ return;
+ }
+
+ if (mpr_prop_type->data_type != RNA_property_type(prop)) {
+ const int manipulator_type_index = RNA_enum_from_value(rna_enum_property_type_items, mpr_prop_type->data_type);
+ const int prop_type_index = RNA_enum_from_value(rna_enum_property_type_items, RNA_property_type(prop));
+ BLI_assert((manipulator_type_index != -1) && (prop_type_index == -1));
+
+ BKE_reportf(reports, RPT_ERROR, "Manipulator target '%s.%s' expects '%s', '%s.%s' is '%s'",
+ mpr->type->idname, target_propname,
+ rna_enum_property_type_items[manipulator_type_index].identifier,
+ RNA_struct_identifier(ptr->type), propname,
+ rna_enum_property_type_items[prop_type_index].identifier);
+ return;
+ }
+
+ if (RNA_property_array_check(prop)) {
+ if (index == -1) {
+ const int prop_array_length = RNA_property_array_length(ptr, prop);
+ if (mpr_prop_type->array_length != prop_array_length) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Manipulator target property '%s.%s' expects an array of length %d, found %d",
+ mpr->type->idname, target_propname,
+ mpr_prop_type->array_length,
+ prop_array_length);
+ return;
+ }
+ }
+ }
+ else {
+ if (mpr_prop_type->array_length != 1) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Manipulator target property '%s.%s' expects an array of length %d",
+ mpr->type->idname, target_propname,
+ mpr_prop_type->array_length);
+ return;
+ }
+ }
+
+ if (index >= mpr_prop_type->array_length) {
+ BKE_reportf(reports, RPT_ERROR, "Manipulator target property '%s.%s', index %d must be below %d",
+ mpr->type->idname, target_propname, index, mpr_prop_type->array_length);
+ return;
+ }
+
+ WM_manipulator_target_property_def_rna_ptr(mpr, mpr_prop_type, ptr, prop, index);
+}
+
+static PointerRNA rna_manipulator_target_set_operator(
+ wmManipulator *mpr, ReportList *reports, const char *opname)
+{
+ wmOperatorType *ot;
+
+ ot = WM_operatortype_find(opname, 0); /* print error next */
+ if (!ot || !ot->srna) {
+ BKE_reportf(reports, RPT_ERROR, "%s '%s'", ot ? "unknown operator" : "operator missing srna", opname);
+ return PointerRNA_NULL;
+ }
+
+ /* For the return value to be usable, we need 'PointerRNA.data' to be set. */
+ IDProperty *properties;
+ {
+ IDPropertyTemplate val = {0};
+ properties = IDP_New(IDP_GROUP, &val, "wmManipulatorProperties");
+ }
+
+ WM_manipulator_set_operator(mpr, ot, properties);
+
+ return mpr->op_data.ptr;
+}
+
+#else
+
+void RNA_api_manipulator(StructRNA *srna)
+{
+ /* Utility draw functions, since we don't expose new OpenGL drawing wrappers via Python yet.
+ * exactly how these should be exposed isn't totally clear.
+ * However it's probably good to have some high level API's for this anyway.
+ * Just note that this could be re-worked once tests are done.
+ */
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ /* -------------------------------------------------------------------- */
+ /* Primitive Shapes */
+
+ /* draw_preset_box */
+ func = RNA_def_function(srna, "draw_preset_box", "rna_manipulator_draw_preset_box");
+ RNA_def_function_ui_description(func, "Draw a box");
+ parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_flag(parm, PARM_REQUIRED);
+ RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(parm, "", "The matrix to transform");
+ RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+
+ /* draw_preset_box */
+ func = RNA_def_function(srna, "draw_preset_arrow", "rna_manipulator_draw_preset_arrow");
+ RNA_def_function_ui_description(func, "Draw a box");
+ parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_flag(parm, PARM_REQUIRED);
+ RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(parm, "", "The matrix to transform");
+ RNA_def_enum(func, "axis", rna_enum_object_axis_items, 2, "", "Arrow Orientation");
+ RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+
+ func = RNA_def_function(srna, "draw_preset_circle", "rna_manipulator_draw_preset_circle");
+ RNA_def_function_ui_description(func, "Draw a box");
+ parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+ RNA_def_property_flag(parm, PARM_REQUIRED);
+ RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_ui_text(parm, "", "The matrix to transform");
+ RNA_def_enum(func, "axis", rna_enum_object_axis_items, 2, "", "Arrow Orientation");
+ RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+
+ /* -------------------------------------------------------------------- */
+ /* Other Shapes */
+
+ /* draw_preset_facemap */
+ func = RNA_def_function(srna, "draw_preset_facemap", "rna_manipulator_draw_preset_facemap");
+ RNA_def_function_ui_description(func, "Draw the face-map of a mesh object");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ parm = RNA_def_pointer(func, "object", "Object", "", "Object");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ RNA_def_int(func, "facemap", 0, 0, INT_MAX, "Face map index", "", 0, INT_MAX);
+ RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+
+
+ /* -------------------------------------------------------------------- */
+ /* Property API */
+
+ /* note, 'target_set_handler' is defined in 'bpy_rna_manipulator.c' */
+ func = RNA_def_function(srna, "target_set_prop", "rna_manipulator_target_set_prop");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "");
+ parm = RNA_def_string(func, "target", NULL, 0, "", "Target property");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* similar to UILayout.prop */
+ parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_int(func, "index", -1, -1, INT_MAX, "", "", -1, INT_MAX); /* RNA_NO_INDEX == -1 */
+
+ func = RNA_def_function(srna, "target_set_operator", "rna_manipulator_target_set_operator");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(
+ func,"Operator to run when activating the manipulator "
+ "(overrides property targets)");
+ parm = RNA_def_string(func, "operator", NULL, 0, "", "Target operator");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* similar to UILayout.operator */
+ parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "Operator properties to fill in");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_function_return(func, parm);
+
+}
+
+
+void RNA_api_manipulatorgroup(StructRNA *UNUSED(srna))
+{
+ /* nothing yet */
+}
+
+#endif
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index be4db6477fe..967e90d22cb 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -65,6 +65,7 @@ set(SRC
bpy_intern_string.c
bpy_library_load.c
bpy_library_write.c
+ bpy_manipulator_wrap.c
bpy_operator.c
bpy_operator_wrap.c
bpy_path.c
@@ -75,6 +76,7 @@ set(SRC
bpy_rna_callback.c
bpy_rna_driver.c
bpy_rna_id_collection.c
+ bpy_rna_manipulator.c
bpy_traceback.c
bpy_util.c
bpy_utils_previews.c
@@ -97,6 +99,7 @@ set(SRC
bpy_driver.h
bpy_intern_string.h
bpy_library.h
+ bpy_manipulator_wrap.h
bpy_operator.h
bpy_operator_wrap.h
bpy_path.h
@@ -106,6 +109,7 @@ set(SRC
bpy_rna_callback.h
bpy_rna_driver.h
bpy_rna_id_collection.h
+ bpy_rna_manipulator.h
bpy_traceback.h
bpy_util.h
bpy_utils_previews.h
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 5bbfb4912e6..4a29d4f8da1 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -46,6 +46,7 @@
#include "bpy_rna.h"
#include "bpy_app.h"
#include "bpy_rna_id_collection.h"
+#include "bpy_rna_manipulator.h"
#include "bpy_props.h"
#include "bpy_library.h"
#include "bpy_operator.h"
@@ -327,6 +328,8 @@ void BPy_init_modules(void)
BPY_rna_id_collection_module(mod);
+ BPY_rna_manipulator_module(mod);
+
bpy_import_test("bpy_types");
PyModule_AddObject(mod, "data", BPY_rna_module()); /* imports bpy_types by running this */
bpy_import_test("bpy_types");
diff --git a/source/blender/python/intern/bpy_intern_string.c b/source/blender/python/intern/bpy_intern_string.c
index e9d84b2099b..6911e985e93 100644
--- a/source/blender/python/intern/bpy_intern_string.c
+++ b/source/blender/python/intern/bpy_intern_string.c
@@ -34,7 +34,7 @@
#include "BLI_utildefines.h"
-static PyObject *bpy_intern_str_arr[15];
+static PyObject *bpy_intern_str_arr[16];
PyObject *bpy_intern_str___doc__;
PyObject *bpy_intern_str___main__;
@@ -44,6 +44,7 @@ PyObject *bpy_intern_str___slots__;
PyObject *bpy_intern_str_attr;
PyObject *bpy_intern_str_bl_property;
PyObject *bpy_intern_str_bl_rna;
+PyObject *bpy_intern_str_bl_target_properties;
PyObject *bpy_intern_str_bpy_types;
PyObject *bpy_intern_str_frame;
PyObject *bpy_intern_str_order;
@@ -67,6 +68,7 @@ void bpy_intern_string_init(void)
BPY_INTERN_STR(bpy_intern_str_attr, "attr");
BPY_INTERN_STR(bpy_intern_str_bl_property, "bl_property");
BPY_INTERN_STR(bpy_intern_str_bl_rna, "bl_rna");
+ BPY_INTERN_STR(bpy_intern_str_bl_target_properties, "bl_target_properties");
BPY_INTERN_STR(bpy_intern_str_bpy_types, "bpy.types");
BPY_INTERN_STR(bpy_intern_str_frame, "frame");
BPY_INTERN_STR(bpy_intern_str_order, "order");
diff --git a/source/blender/python/intern/bpy_intern_string.h b/source/blender/python/intern/bpy_intern_string.h
index 66c469f70bc..998c312c321 100644
--- a/source/blender/python/intern/bpy_intern_string.h
+++ b/source/blender/python/intern/bpy_intern_string.h
@@ -38,6 +38,7 @@ extern PyObject *bpy_intern_str___slots__;
extern PyObject *bpy_intern_str_attr;
extern PyObject *bpy_intern_str_bl_property;
extern PyObject *bpy_intern_str_bl_rna;
+extern PyObject *bpy_intern_str_bl_target_properties;
extern PyObject *bpy_intern_str_bpy_types;
extern PyObject *bpy_intern_str_frame;
extern PyObject *bpy_intern_str_order;
diff --git a/source/blender/python/intern/bpy_manipulator_wrap.c b/source/blender/python/intern/bpy_manipulator_wrap.c
new file mode 100644
index 00000000000..53b6285e880
--- /dev/null
+++ b/source/blender/python/intern/bpy_manipulator_wrap.c
@@ -0,0 +1,231 @@
+/*
+ * ***** 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 *****
+ */
+
+/** \file blender/python/intern/bpy_manipulator_wrap.c
+ * \ingroup pythonintern
+ *
+ * This file is so Python can define widget-group's that C can call into.
+ * The generic callback functions for Python widget-group are defines in
+ * 'rna_wm.c', some calling into functions here to do python specific
+ * functionality.
+ *
+ * \note This follows 'bpy_operator_wrap.c' very closely.
+ * Keep in sync unless there is good reason not to!
+ */
+
+#include <Python.h>
+
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "bpy_rna.h"
+#include "bpy_intern_string.h"
+#include "bpy_manipulator_wrap.h" /* own include */
+
+/* we may want to add, but not now */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Manipulator
+ * \{ */
+
+
+static bool bpy_manipulatortype_target_property_def(
+ wmManipulatorType *wt, PyObject *item)
+{
+ /* Note: names based on 'rna_rna.c' */
+ PyObject *empty_tuple = PyTuple_New(0);
+ static const char * const _keywords[] = {"id", "type", "array_length", NULL};
+ static _PyArg_Parser _parser = {"|$ssi:register_class", _keywords, 0};
+
+ struct {
+ char *id;
+ char *type_id; int type;
+ int array_length;
+ } params = {
+ .id = NULL, /* not optional */
+ .type = PROP_FLOAT,
+ .type_id = NULL,
+ .array_length = 1,
+ };
+
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ empty_tuple, item,
+ &_parser,
+ &params.id,
+ &params.type_id,
+ &params.array_length))
+ {
+ goto fail;
+ }
+
+ if (params.id == NULL) {
+ PyErr_SetString(PyExc_ValueError, "'id' argument not given");
+ goto fail;
+ }
+
+ if ((params.type_id != NULL) &&
+ pyrna_enum_value_from_id(
+ rna_enum_property_type_items, params.type_id, &params.type, "'type' enum value") == -1)
+ {
+ goto fail;
+ }
+ else {
+ params.type = rna_enum_property_type_items[params.type].value;
+ }
+
+ if ((params.array_length < 1 || params.array_length > RNA_MAX_ARRAY_LENGTH)) {
+ PyErr_SetString(PyExc_ValueError, "'array_length' out of range");
+ goto fail;
+ }
+
+ WM_manipulatortype_target_property_def(wt, params.id, params.type, params.array_length);
+ Py_DECREF(empty_tuple);
+ return true;
+
+fail:
+ Py_DECREF(empty_tuple);
+ return false;
+}
+
+static void manipulator_properties_init(wmManipulatorType *wt)
+{
+ PyTypeObject *py_class = wt->ext.data;
+ RNA_struct_blender_type_set(wt->ext.srna, wt);
+
+ /* only call this so pyrna_deferred_register_class gives a useful error
+ * WM_operatortype_append_ptr will call RNA_def_struct_identifier
+ * later */
+ RNA_def_struct_identifier(wt->srna, wt->idname);
+
+ if (pyrna_deferred_register_class(wt->srna, py_class) != 0) {
+ PyErr_Print(); /* failed to register operator props */
+ PyErr_Clear();
+ }
+
+ /* Extract target property definitions from 'bl_target_properties' */
+ {
+ /* picky developers will notice that 'bl_targets' won't work with inheritance
+ * get direct from the dict to avoid raising a load of attribute errors (yes this isnt ideal) - campbell */
+ PyObject *py_class_dict = py_class->tp_dict;
+ PyObject *bl_target_properties = PyDict_GetItem(py_class_dict, bpy_intern_str_bl_target_properties);
+ PyObject *bl_target_properties_fast;
+
+ if (!(bl_target_properties_fast = PySequence_Fast(bl_target_properties, "bl_target_properties sequence"))) {
+ /* PySequence_Fast sets the error */
+ PyErr_Print();
+ PyErr_Clear();
+ return;
+ }
+
+ const uint items_len = PySequence_Fast_GET_SIZE(bl_target_properties_fast);
+ PyObject **items = PySequence_Fast_ITEMS(bl_target_properties_fast);
+
+ for (uint i = 0; i < items_len; i++) {
+ if (!bpy_manipulatortype_target_property_def(wt, items[i])) {
+ PyErr_Print();
+ PyErr_Clear();
+ break;
+ }
+ }
+
+ Py_DECREF(bl_target_properties_fast);
+ }
+}
+
+void BPY_RNA_manipulator_wrapper(wmManipulatorType *wt, void *userdata)
+{
+ /* take care not to overwrite anything set in
+ * WM_manipulatormaptype_group_link_ptr before opfunc() is called */
+ StructRNA *srna = wt->srna;
+ *wt = *((wmManipulatorType *)userdata);
+ wt->srna = srna; /* restore */
+
+ /* don't do translations here yet */
+#if 0
+ /* Use i18n context from ext.srna if possible (py manipulatorgroups). */
+ if (wt->ext.srna) {
+ RNA_def_struct_translation_context(wt->srna, RNA_struct_translation_context(wt->ext.srna));
+ }
+#endif
+
+ wt->struct_size = sizeof(wmManipulator);
+
+ manipulator_properties_init(wt);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Manipulator Group
+ * \{ */
+
+static void manipulatorgroup_properties_init(wmManipulatorGroupType *wgt)
+{
+#ifdef USE_SRNA
+ PyTypeObject *py_class = wgt->ext.data;
+#endif
+ RNA_struct_blender_type_set(wgt->ext.srna, wgt);
+
+#ifdef USE_SRNA
+ /* only call this so pyrna_deferred_register_class gives a useful error
+ * WM_operatortype_append_ptr will call RNA_def_struct_identifier
+ * later */
+ RNA_def_struct_identifier(wgt->srna, wgt->idname);
+
+ if (pyrna_deferred_register_class(wgt->srna, py_class) != 0) {
+ PyErr_Print(); /* failed to register operator props */
+ PyErr_Clear();
+ }
+#endif
+}
+
+void BPY_RNA_manipulatorgroup_wrapper(wmManipulatorGroupType *wgt, void *userdata)
+{
+ /* take care not to overwrite anything set in
+ * WM_manipulatormaptype_group_link_ptr before opfunc() is called */
+#ifdef USE_SRNA
+ StructRNA *srna = wgt->srna;
+#endif
+ *wgt = *((wmManipulatorGroupType *)userdata);
+#ifdef USE_SRNA
+ wgt->srna = srna; /* restore */
+#endif
+
+#ifdef USE_SRNA
+ /* Use i18n context from ext.srna if possible (py manipulatorgroups). */
+ if (wgt->ext.srna) {
+ RNA_def_struct_translation_context(wgt->srna, RNA_struct_translation_context(wgt->ext.srna));
+ }
+#endif
+
+ manipulatorgroup_properties_init(wgt);
+}
+
+/** \} */
+
diff --git a/source/blender/python/intern/bpy_manipulator_wrap.h b/source/blender/python/intern/bpy_manipulator_wrap.h
new file mode 100644
index 00000000000..3f739e26059
--- /dev/null
+++ b/source/blender/python/intern/bpy_manipulator_wrap.h
@@ -0,0 +1,36 @@
+/*
+ * ***** 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 *****
+ */
+
+/** \file blender/python/intern/bpy_manipulator_wrap.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_MANIPULATOR_WRAP_H__
+#define __BPY_MANIPULATOR_WRAP_H__
+
+struct wmManipulatorType;
+struct wmManipulatorGroupType;
+
+/* exposed to rna/wm api */
+void BPY_RNA_manipulator_wrapper(struct wmManipulatorType *wt, void *userdata);
+void BPY_RNA_manipulatorgroup_wrapper(struct wmManipulatorGroupType *wgt, void *userdata);
+
+#endif /* __BPY_MANIPULATOR_WRAP_H__ */
+
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 6f3d0145d87..51e179fb317 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1839,19 +1839,28 @@ static int pyrna_py_to_prop(
* class mixing if this causes problems in the future it should be removed.
*/
if ((ptr_type == &RNA_AnyType) &&
- (BPy_StructRNA_Check(value)) &&
- (RNA_struct_is_a(((BPy_StructRNA *)value)->ptr.type, &RNA_Operator)))
+ (BPy_StructRNA_Check(value)))
{
- value = PyObject_GetAttr(value, bpy_intern_str_properties);
- value_new = value;
+ const StructRNA *base_type =
+ RNA_struct_base_child_of(((const BPy_StructRNA *)value)->ptr.type, NULL);
+ if (ELEM(base_type, &RNA_Operator, &RNA_Manipulator)) {
+ value = PyObject_GetAttr(value, bpy_intern_str_properties);
+ value_new = value;
+ }
}
-
- /* if property is an OperatorProperties pointer and value is a map,
+ /* if property is an OperatorProperties/ManipulatorProperties pointer and value is a map,
* forward back to pyrna_pydict_to_props */
- if (RNA_struct_is_a(ptr_type, &RNA_OperatorProperties) && PyDict_Check(value)) {
- PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
- return pyrna_pydict_to_props(&opptr, value, false, error_prefix);
+ if (PyDict_Check(value)) {
+ const StructRNA *base_type = RNA_struct_base_child_of(ptr_type, NULL);
+ if (base_type == &RNA_OperatorProperties) {
+ PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
+ return pyrna_pydict_to_props(&opptr, value, false, error_prefix);
+ }
+ else if (base_type == &RNA_ManipulatorProperties) {
+ PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
+ return pyrna_pydict_to_props(&opptr, value, false, error_prefix);
+ }
}
/* another exception, allow to pass a collection as an RNA property */
@@ -6926,7 +6935,7 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self)
StructRNA *srna = itemptr.data;
StructRNA *srna_base = RNA_struct_base(itemptr.data);
/* skip own operators, these double up [#29666] */
- if (srna_base == &RNA_Operator) {
+ if (ELEM(srna_base, &RNA_Operator, &RNA_Manipulator)) {
/* do nothing */
}
else {
@@ -7456,7 +7465,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
PyGILState_STATE gilstate;
#ifdef USE_PEDANTIC_WRITE
- const bool is_operator = RNA_struct_is_a(ptr->type, &RNA_Operator);
+ const bool is_readonly_init = !(RNA_struct_is_a(ptr->type, &RNA_Operator) ||
+ RNA_struct_is_a(ptr->type, &RNA_Manipulator));
// const char *func_id = RNA_function_identifier(func); /* UNUSED */
/* testing, for correctness, not operator and not draw function */
const bool is_readonly = !(RNA_function_flag(func) & FUNC_ALLOW_WRITE);
@@ -7521,7 +7531,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
if (py_class->tp_init) {
#ifdef USE_PEDANTIC_WRITE
const int prev_write = rna_disallow_writes;
- rna_disallow_writes = is_operator ? false : true; /* only operators can write on __init__ */
+ rna_disallow_writes = is_readonly_init ? false : true; /* only operators can write on __init__ */
#endif
/* true in most cases even when the class its self doesn't define an __init__ function. */
diff --git a/source/blender/python/intern/bpy_rna_manipulator.c b/source/blender/python/intern/bpy_rna_manipulator.c
new file mode 100644
index 00000000000..245735f679e
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_manipulator.c
@@ -0,0 +1,341 @@
+/*
+ * ***** 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 *****
+ */
+
+/** \file blender/python/intern/bpy_rna_manipulator.c
+ * \ingroup pythonintern
+ *
+ * .
+ */
+
+#include <Python.h>
+#include <stddef.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_main.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "bpy_util.h"
+#include "bpy_rna_manipulator.h"
+
+#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+#include "RNA_enum_types.h"
+
+#include "bpy_rna.h"
+
+enum {
+ BPY_MANIPULATOR_FN_SLOT_GET = 0,
+ BPY_MANIPULATOR_FN_SLOT_SET,
+ BPY_MANIPULATOR_FN_SLOT_RANGE_GET,
+};
+#define BPY_MANIPULATOR_FN_SLOT_LEN (BPY_MANIPULATOR_FN_SLOT_RANGE_GET + 1)
+
+struct BPyManipulatorHandlerUserData {
+
+ PyObject *fn_slots[BPY_MANIPULATOR_FN_SLOT_LEN];
+};
+
+static void py_rna_manipulator_handler_get_cb(
+ const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data;
+ PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_MANIPULATOR_FN_SLOT_GET], NULL);
+ if (ret == NULL) {
+ goto fail;
+ }
+
+ if (mpr_prop->type->data_type == PROP_FLOAT) {
+ float *value = value_p;
+ if (mpr_prop->type->array_length == 1) {
+ if (((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) == 0) {
+ goto fail;
+ }
+ }
+ else {
+ if (PyC_AsArray(value, ret, mpr_prop->type->array_length, &PyFloat_Type, false,
+ "Manipulator get callback: ") == -1)
+ {
+ goto fail;
+ }
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
+ goto fail;
+ }
+
+ Py_DECREF(ret);
+
+ PyGILState_Release(gilstate);
+ return;
+
+fail:
+ PyErr_Print();
+ PyErr_Clear();
+
+ PyGILState_Release(gilstate);
+}
+
+static void py_rna_manipulator_handler_set_cb(
+ const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop,
+ const void *value_p)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data;
+
+ PyObject *args = PyTuple_New(1);
+
+ if (mpr_prop->type->data_type == PROP_FLOAT) {
+ const float *value = value_p;
+ PyObject *py_value;
+ if (mpr_prop->type->array_length == 1) {
+ py_value = PyFloat_FromDouble(*value);
+ }
+ else {
+ py_value = PyC_FromArray((void *)value, mpr_prop->type->array_length, &PyFloat_Type, false,
+ "Manipulator set callback: ");
+ }
+ if (py_value == NULL) {
+ goto fail;
+ }
+ PyTuple_SET_ITEM(args, 0, py_value);
+ }
+ else {
+ PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
+ goto fail;
+ }
+
+ PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_MANIPULATOR_FN_SLOT_SET], args);
+ if (ret == NULL) {
+ goto fail;
+ }
+ Py_DECREF(ret);
+
+ PyGILState_Release(gilstate);
+ return;
+
+fail:
+ PyErr_Print();
+ PyErr_Clear();
+
+ Py_DECREF(args);
+
+ PyGILState_Release(gilstate);
+}
+
+static void py_rna_manipulator_handler_range_get_cb(
+ const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop,
+ void *value_p)
+{
+ struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data;
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_MANIPULATOR_FN_SLOT_RANGE_GET], NULL);
+ if (ret == NULL) {
+ goto fail;
+ }
+
+ if (!PyTuple_Check(ret)) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected a tuple, not %.200s",
+ Py_TYPE(ret)->tp_name);
+ goto fail;
+ }
+
+ if (PyTuple_GET_SIZE(ret) != 2) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected a tuple of size 2, not %d",
+ PyTuple_GET_SIZE(ret));
+ goto fail;
+ }
+
+ if (mpr_prop->type->data_type == PROP_FLOAT) {
+ float range[2];
+ for (int i = 0; i < 2; i++) {
+ if (((range[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(ret, i))) == -1.0f && PyErr_Occurred()) == 0) {
+ /* pass */
+ }
+ else {
+ goto fail;
+ }
+ }
+ memcpy(value_p, range, sizeof(range));
+ }
+ else {
+ PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
+ goto fail;
+ }
+
+ Py_DECREF(ret);
+ PyGILState_Release(gilstate);
+ return;
+
+fail:
+ Py_XDECREF(ret);
+
+ PyErr_Print();
+ PyErr_Clear();
+
+ PyGILState_Release(gilstate);
+}
+
+static void py_rna_manipulator_handler_free_cb(
+ const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop)
+{
+ struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data;
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ for (int i = 0; i < BPY_MANIPULATOR_FN_SLOT_LEN; i++) {
+ Py_XDECREF(data->fn_slots[i]);
+ }
+ PyGILState_Release(gilstate);
+
+ MEM_freeN(data);
+
+}
+
+PyDoc_STRVAR(bpy_manipulator_target_set_handler_doc,
+".. method:: target_set_handler(target, get, set, range=None):\n"
+"\n"
+" Assigns callbacks to a manipulators property.\n"
+"\n"
+" :arg get: Function that returns the value for this property (single value or sequence).\n"
+" :type get: callable\n"
+" :arg set: Function that takes a single value argument and applies it.\n"
+" :type set: callable\n"
+" :arg range: Function that returns a (min, max) tuple for manipulators that use a range.\n"
+" :type range: callable\n"
+);
+static PyObject *bpy_manipulator_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+ /* Note: this is a counter-part to functions:
+ * 'Manipulator.target_set_prop & target_set_operator'
+ * (see: rna_wm_manipulator_api.c). conventions should match. */
+ static const char * const _keywords[] = {"self", "target", "get", "set", "range", NULL};
+ static _PyArg_Parser _parser = {"Os|$OOO:target_set_handler", _keywords, 0};
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ struct {
+ PyObject *self;
+ char *target;
+ PyObject *py_fn_slots[BPY_MANIPULATOR_FN_SLOT_LEN];
+ } params = {
+ .self = NULL,
+ .target = NULL,
+ .py_fn_slots = {NULL},
+ };
+
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds,
+ &_parser,
+ &params.self,
+ &params.target,
+ &params.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_GET],
+ &params.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_SET],
+ &params.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_RANGE_GET]))
+ {
+ goto fail;
+ }
+
+ wmManipulator *mpr = ((BPy_StructRNA *)params.self)->ptr.data;
+
+ const wmManipulatorPropertyType *mpr_prop_type =
+ WM_manipulatortype_target_property_find(mpr->type, params.target);
+ if (mpr_prop_type == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "Manipulator target property '%s.%s' not found",
+ mpr->type->idname, params.target);
+ goto fail;
+ }
+
+ {
+ const int slots_required = 2;
+ const int slots_start = 2;
+ for (int i = 0; i < BPY_MANIPULATOR_FN_SLOT_LEN; i++) {
+ if (params.py_fn_slots[i] == NULL) {
+ if (i < slots_required) {
+ PyErr_Format(PyExc_ValueError, "Argument '%s' not given", _keywords[slots_start + i]);
+ goto fail;
+ }
+ }
+ else if (!PyCallable_Check(params.py_fn_slots[i])) {
+ PyErr_Format(PyExc_ValueError, "Argument '%s' not callable", _keywords[slots_start + i]);
+ goto fail;
+ }
+ }
+ }
+
+ struct BPyManipulatorHandlerUserData *data = MEM_callocN(sizeof(*data), __func__);
+
+ for (int i = 0; i < BPY_MANIPULATOR_FN_SLOT_LEN; i++) {
+ data->fn_slots[i] = params.py_fn_slots[i];
+ Py_XINCREF(params.py_fn_slots[i]);
+ }
+
+ WM_manipulator_target_property_def_func_ptr(
+ mpr, mpr_prop_type,
+ &(const struct wmManipulatorPropertyFnParams) {
+ .value_get_fn = py_rna_manipulator_handler_get_cb,
+ .value_set_fn = py_rna_manipulator_handler_set_cb,
+ .range_get_fn = py_rna_manipulator_handler_range_get_cb,
+ .free_fn = py_rna_manipulator_handler_free_cb,
+ .user_data = data,
+ });
+
+ PyGILState_Release(gilstate);
+
+ Py_RETURN_NONE;
+
+fail:
+ PyGILState_Release(gilstate);
+ return NULL;
+}
+
+int BPY_rna_manipulator_module(PyObject *mod_par)
+{
+ static PyMethodDef method_def = {
+ "target_set_handler", (PyCFunction)bpy_manipulator_target_set_handler, METH_VARARGS | METH_KEYWORDS,
+ bpy_manipulator_target_set_handler_doc};
+
+ PyObject *func = PyCFunction_New(&method_def, NULL);
+ PyObject *func_inst = PyInstanceMethod_New(func);
+
+
+ /* TODO, return a type that binds nearly to a method. */
+ PyModule_AddObject(mod_par, "_rna_manipulator_target_set_handler", func_inst);
+
+ return 0;
+}
+
+
diff --git a/source/blender/python/intern/bpy_rna_manipulator.h b/source/blender/python/intern/bpy_rna_manipulator.h
new file mode 100644
index 00000000000..b6f3a2e651d
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_manipulator.h
@@ -0,0 +1,32 @@
+/*
+ * ***** 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.
+ *
+ * Contributor(s): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_rna_manipulator.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_RNA_MANIPULATOR_H__
+#define __BPY_RNA_MANIPULATOR_H__
+
+int BPY_rna_manipulator_module(PyObject *);
+
+#endif /* __BPY_RNA_MANIPULATOR_H__ */
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 30f67a38420..ea0a28d57f7 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -133,6 +133,7 @@ struct wmOperator;
struct wmOperatorType;
struct wmWindow;
struct wmWindowManager;
+struct wmManipulatorGroupType;
struct wmManipulatorMap;
@@ -164,6 +165,7 @@ struct wmManipulatorMap;
#include "../blender/editors/include/ED_keyframes_edit.h"
#include "../blender/editors/include/ED_keyframing.h"
#include "../blender/editors/include/ED_lattice.h"
+#include "../blender/editors/include/ED_manipulator_library.h"
#include "../blender/editors/include/ED_mball.h"
#include "../blender/editors/include/ED_mesh.h"
#include "../blender/editors/include/ED_node.h"
@@ -186,6 +188,7 @@ struct wmManipulatorMap;
#include "../blender/gpu/GPU_immediate.h"
#include "../blender/gpu/GPU_matrix.h"
#include "../blender/python/BPY_extern.h"
+#include "../blender/python/intern/bpy_manipulator_wrap.h"
#include "../blender/render/extern/include/RE_engine.h"
#include "../blender/render/extern/include/RE_pipeline.h"
#include "../blender/render/extern/include/RE_render_ext.h"
@@ -358,6 +361,31 @@ void WM_jobs_callbacks(struct wmJob *job,
void WM_jobs_start(struct wmWindowManager *wm, struct wmJob *job) RET_NONE
void WM_report(ReportType type, const char *message) RET_NONE
+void BPY_RNA_manipulatorgroup_wrapper(struct wmManipulatorGroupType *wgt, void *userdata) RET_NONE
+void BPY_RNA_manipulator_wrapper(struct wmManipulatorType *wgt, void *userdata) RET_NONE
+
+PointerRNA *WM_manipulator_set_operator(struct wmManipulator *mpr, struct wmOperatorType *ot, struct IDProperty *properties) RET_NULL
+const struct wmManipulatorPropertyType *WM_manipulatortype_target_property_find(const struct wmManipulatorType *wt, const char *idname) RET_NULL
+const struct wmManipulatorType *WM_manipulatortype_find(const char *idname, bool quiet) RET_NULL
+struct wmManipulator *WM_manipulator_new_ptr(const struct wmManipulatorType *wt, struct wmManipulatorGroup *mgroup, const char *name, struct PointerRNA *properties) RET_NULL
+struct wmManipulatorGroupType *WM_manipulatorgrouptype_append_ptr(void (*mnpfunc)(struct wmManipulatorGroupType *, void *), void *userdata) RET_NULL
+struct wmManipulatorGroupType *WM_manipulatorgrouptype_find(const char *idname, bool quiet) RET_NULL
+void WM_manipulator_free(ListBase *manipulatorlist, struct wmManipulatorMap *mmap, struct wmManipulator *mpr, struct bContext *C) RET_NONE
+void WM_manipulator_group_add_ptr(struct wmManipulatorGroupType *wgt) RET_NONE
+void WM_manipulator_group_add_ptr_ex(struct wmManipulatorGroupType *wgt, struct wmManipulatorMapType *mmap_type) RET_NONE
+void WM_manipulator_group_remove_ptr(struct Main *bmain, struct wmManipulatorGroupType *wgt) RET_NONE
+void WM_manipulator_name_set(struct wmManipulatorGroup *mgroup, struct wmManipulator *mpr, const char *name) RET_NONE
+void WM_manipulator_target_property_def_rna_ptr(struct wmManipulator *mpr, const struct wmManipulatorPropertyType *mpr_prop_type, struct PointerRNA *ptr, struct PropertyRNA *prop, int index) RET_NONE
+void WM_manipulatorgrouptype_remove_ptr(struct wmManipulatorGroupType *wt) RET_NONE
+void WM_manipulatormaptype_group_unlink(struct bContext *C, struct Main *bmain, struct wmManipulatorMapType *mmap_type, const struct wmManipulatorGroupType *wgt) RET_NONE
+void WM_manipulatortype_append_ptr(void (*mnpfunc)(struct wmManipulatorType *, void *), void *userdata) RET_NONE
+void WM_manipulatortype_remove_ptr(struct wmManipulatorType *wt) RET_NONE
+
+void ED_manipulator_draw_preset_box(const struct wmManipulator *mpr, float mat[4][4], int select_id) RET_NONE
+void ED_manipulator_draw_preset_arrow(const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id) RET_NONE
+void ED_manipulator_draw_preset_circle(const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id) RET_NONE
+void ED_manipulator_draw_preset_facemap(const struct wmManipulator *mpr, struct Scene *scene, struct Object *ob, const int facemap, int select_id) RET_NONE
+
struct wmManipulatorMapType *WM_manipulatormaptype_find(const struct wmManipulatorMapType_Params *wmap_params) RET_NULL
struct wmManipulatorMapType *WM_manipulatormaptype_ensure(const struct wmManipulatorMapType_Params *wmap_params) RET_NULL
struct wmManipulatorMap *WM_manipulatormap_new_from_type(const struct wmManipulatorMapType_Params *wmap_params) RET_NULL