forked from bartvdbraak/blender
Manipulator: Python API
Initial support for Python/Manipulator integration from 'custom-manipulators' branch. Supports: - Registering custom manipulators & manipulator-groups. - Modifying RNA properties, custom values via get/set callbacks, or invoking an operator. - Drawing shape presets for Python defined manipulators (arrow, circle, face-maps) Limitations: - Only float properties supported. - Drawing only supported via shape presets. (we'll likely want a way to define custom geometry or draw directly). - When to refresh, recalculate manipulators will likely need integration with notifier system. Development will be continued in the 2.8 branch
This commit is contained in:
parent
c9e33b36de
commit
28b2f1c305
@ -612,6 +612,8 @@ function(SETUP_BLENDER_SORTED_LIBS)
|
|||||||
bf_physics
|
bf_physics
|
||||||
bf_nodes
|
bf_nodes
|
||||||
bf_rna
|
bf_rna
|
||||||
|
bf_editor_manipulator_library # rna -> manipulator bad-level calls
|
||||||
|
bf_python
|
||||||
bf_imbuf
|
bf_imbuf
|
||||||
bf_blenlib
|
bf_blenlib
|
||||||
bf_depsgraph
|
bf_depsgraph
|
||||||
|
29
doc/python_api/examples/bpy.types.ManipulatorGroup.py
Normal file
29
doc/python_api/examples/bpy.types.ManipulatorGroup.py
Normal file
@ -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
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
@ -332,6 +332,9 @@ except ImportError:
|
|||||||
# to avoid having to match Blender's source tree.
|
# to avoid having to match Blender's source tree.
|
||||||
EXTRA_SOURCE_FILES = (
|
EXTRA_SOURCE_FILES = (
|
||||||
"../../../release/scripts/templates_py/bmesh_simple.py",
|
"../../../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/operator_simple.py",
|
||||||
"../../../release/scripts/templates_py/ui_panel_simple.py",
|
"../../../release/scripts/templates_py/ui_panel_simple.py",
|
||||||
"../../../release/scripts/templates_py/ui_previews_custom_icon.py",
|
"../../../release/scripts/templates_py/ui_previews_custom_icon.py",
|
||||||
|
@ -592,6 +592,35 @@ class OrderedMeta(RNAMeta):
|
|||||||
return OrderedDictMini() # collections.OrderedDict()
|
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
|
# Only defined so operators members can be used by accessing self.order
|
||||||
# with doc generation 'self.properties.bl_rna.properties' can fail
|
# with doc generation 'self.properties.bl_rna.properties' can fail
|
||||||
class Operator(StructRNA, metaclass=OrderedMeta):
|
class Operator(StructRNA, metaclass=OrderedMeta):
|
||||||
|
224
release/scripts/templates_py/manipulator_operator.py
Normal file
224
release/scripts/templates_py/manipulator_operator.py
Normal file
@ -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()
|
45
release/scripts/templates_py/manipulator_operator_target.py
Normal file
45
release/scripts/templates_py/manipulator_operator_target.py
Normal file
@ -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)
|
42
release/scripts/templates_py/manipulator_simple.py
Normal file
42
release/scripts/templates_py/manipulator_simple.py
Normal file
@ -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)
|
@ -127,6 +127,7 @@ set(APISRC
|
|||||||
rna_ui_api.c
|
rna_ui_api.c
|
||||||
rna_vfont_api.c
|
rna_vfont_api.c
|
||||||
rna_wm_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}")
|
string(REGEX REPLACE "rna_([a-zA-Z0-9_-]*).c" "${CMAKE_CURRENT_BINARY_DIR}/rna_\\1_gen.c" GENSRC "${DEFSRC}")
|
||||||
|
@ -3365,7 +3365,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
|
|||||||
{"rna_userdef.c", NULL, RNA_def_userdef},
|
{"rna_userdef.c", NULL, RNA_def_userdef},
|
||||||
{"rna_vfont.c", "rna_vfont_api.c", RNA_def_vfont},
|
{"rna_vfont.c", "rna_vfont_api.c", RNA_def_vfont},
|
||||||
{"rna_wm.c", "rna_wm_api.c", RNA_def_wm},
|
{"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_workspace.c", NULL, RNA_def_workspace},
|
||||||
{"rna_world.c", NULL, RNA_def_world},
|
{"rna_world.c", NULL, RNA_def_world},
|
||||||
{"rna_movieclip.c", NULL, RNA_def_movieclip},
|
{"rna_movieclip.c", NULL, RNA_def_movieclip},
|
||||||
|
@ -71,6 +71,8 @@ EnumPropertyItem rna_enum_window_cursor_items[] = {
|
|||||||
#include "UI_interface.h"
|
#include "UI_interface.h"
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
|
|
||||||
|
#include "WM_types.h"
|
||||||
|
|
||||||
static wmKeyMap *rna_keymap_active(wmKeyMap *km, bContext *C)
|
static wmKeyMap *rna_keymap_active(wmKeyMap *km, bContext *C)
|
||||||
{
|
{
|
||||||
wmWindowManager *wm = CTX_wm_manager(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);
|
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 */
|
/* placeholder data for final implementation of a true progressbar */
|
||||||
static struct wmStaticProgress {
|
static struct wmStaticProgress {
|
||||||
float min;
|
float min;
|
||||||
@ -426,6 +459,18 @@ void RNA_api_wm(StructRNA *srna)
|
|||||||
parm = RNA_def_pointer(func, "timer", "Timer", "", "");
|
parm = RNA_def_pointer(func, "timer", "Timer", "", "");
|
||||||
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
|
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 */
|
/* Progress bar interface */
|
||||||
func = RNA_def_function(srna, "progress_begin", "rna_progress_begin");
|
func = RNA_def_function(srna, "progress_begin", "rna_progress_begin");
|
||||||
RNA_def_function_ui_description(func, "Start progress report");
|
RNA_def_function_ui_description(func, "Start progress report");
|
||||||
|
File diff suppressed because it is too large
Load Diff
254
source/blender/makesrna/intern/rna_wm_manipulator_api.c
Normal file
254
source/blender/makesrna/intern/rna_wm_manipulator_api.c
Normal file
@ -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
|
@ -65,6 +65,7 @@ set(SRC
|
|||||||
bpy_intern_string.c
|
bpy_intern_string.c
|
||||||
bpy_library_load.c
|
bpy_library_load.c
|
||||||
bpy_library_write.c
|
bpy_library_write.c
|
||||||
|
bpy_manipulator_wrap.c
|
||||||
bpy_operator.c
|
bpy_operator.c
|
||||||
bpy_operator_wrap.c
|
bpy_operator_wrap.c
|
||||||
bpy_path.c
|
bpy_path.c
|
||||||
@ -75,6 +76,7 @@ set(SRC
|
|||||||
bpy_rna_callback.c
|
bpy_rna_callback.c
|
||||||
bpy_rna_driver.c
|
bpy_rna_driver.c
|
||||||
bpy_rna_id_collection.c
|
bpy_rna_id_collection.c
|
||||||
|
bpy_rna_manipulator.c
|
||||||
bpy_traceback.c
|
bpy_traceback.c
|
||||||
bpy_util.c
|
bpy_util.c
|
||||||
bpy_utils_previews.c
|
bpy_utils_previews.c
|
||||||
@ -97,6 +99,7 @@ set(SRC
|
|||||||
bpy_driver.h
|
bpy_driver.h
|
||||||
bpy_intern_string.h
|
bpy_intern_string.h
|
||||||
bpy_library.h
|
bpy_library.h
|
||||||
|
bpy_manipulator_wrap.h
|
||||||
bpy_operator.h
|
bpy_operator.h
|
||||||
bpy_operator_wrap.h
|
bpy_operator_wrap.h
|
||||||
bpy_path.h
|
bpy_path.h
|
||||||
@ -106,6 +109,7 @@ set(SRC
|
|||||||
bpy_rna_callback.h
|
bpy_rna_callback.h
|
||||||
bpy_rna_driver.h
|
bpy_rna_driver.h
|
||||||
bpy_rna_id_collection.h
|
bpy_rna_id_collection.h
|
||||||
|
bpy_rna_manipulator.h
|
||||||
bpy_traceback.h
|
bpy_traceback.h
|
||||||
bpy_util.h
|
bpy_util.h
|
||||||
bpy_utils_previews.h
|
bpy_utils_previews.h
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "bpy_rna.h"
|
#include "bpy_rna.h"
|
||||||
#include "bpy_app.h"
|
#include "bpy_app.h"
|
||||||
#include "bpy_rna_id_collection.h"
|
#include "bpy_rna_id_collection.h"
|
||||||
|
#include "bpy_rna_manipulator.h"
|
||||||
#include "bpy_props.h"
|
#include "bpy_props.h"
|
||||||
#include "bpy_library.h"
|
#include "bpy_library.h"
|
||||||
#include "bpy_operator.h"
|
#include "bpy_operator.h"
|
||||||
@ -327,6 +328,8 @@ void BPy_init_modules(void)
|
|||||||
|
|
||||||
BPY_rna_id_collection_module(mod);
|
BPY_rna_id_collection_module(mod);
|
||||||
|
|
||||||
|
BPY_rna_manipulator_module(mod);
|
||||||
|
|
||||||
bpy_import_test("bpy_types");
|
bpy_import_test("bpy_types");
|
||||||
PyModule_AddObject(mod, "data", BPY_rna_module()); /* imports bpy_types by running this */
|
PyModule_AddObject(mod, "data", BPY_rna_module()); /* imports bpy_types by running this */
|
||||||
bpy_import_test("bpy_types");
|
bpy_import_test("bpy_types");
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
#include "BLI_utildefines.h"
|
#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___doc__;
|
||||||
PyObject *bpy_intern_str___main__;
|
PyObject *bpy_intern_str___main__;
|
||||||
@ -44,6 +44,7 @@ PyObject *bpy_intern_str___slots__;
|
|||||||
PyObject *bpy_intern_str_attr;
|
PyObject *bpy_intern_str_attr;
|
||||||
PyObject *bpy_intern_str_bl_property;
|
PyObject *bpy_intern_str_bl_property;
|
||||||
PyObject *bpy_intern_str_bl_rna;
|
PyObject *bpy_intern_str_bl_rna;
|
||||||
|
PyObject *bpy_intern_str_bl_target_properties;
|
||||||
PyObject *bpy_intern_str_bpy_types;
|
PyObject *bpy_intern_str_bpy_types;
|
||||||
PyObject *bpy_intern_str_frame;
|
PyObject *bpy_intern_str_frame;
|
||||||
PyObject *bpy_intern_str_order;
|
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_attr, "attr");
|
||||||
BPY_INTERN_STR(bpy_intern_str_bl_property, "bl_property");
|
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_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_bpy_types, "bpy.types");
|
||||||
BPY_INTERN_STR(bpy_intern_str_frame, "frame");
|
BPY_INTERN_STR(bpy_intern_str_frame, "frame");
|
||||||
BPY_INTERN_STR(bpy_intern_str_order, "order");
|
BPY_INTERN_STR(bpy_intern_str_order, "order");
|
||||||
|
@ -38,6 +38,7 @@ extern PyObject *bpy_intern_str___slots__;
|
|||||||
extern PyObject *bpy_intern_str_attr;
|
extern PyObject *bpy_intern_str_attr;
|
||||||
extern PyObject *bpy_intern_str_bl_property;
|
extern PyObject *bpy_intern_str_bl_property;
|
||||||
extern PyObject *bpy_intern_str_bl_rna;
|
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_bpy_types;
|
||||||
extern PyObject *bpy_intern_str_frame;
|
extern PyObject *bpy_intern_str_frame;
|
||||||
extern PyObject *bpy_intern_str_order;
|
extern PyObject *bpy_intern_str_order;
|
||||||
|
231
source/blender/python/intern/bpy_manipulator_wrap.c
Normal file
231
source/blender/python/intern/bpy_manipulator_wrap.c
Normal file
@ -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,
|
||||||
|
¶ms.id,
|
||||||
|
¶ms.type_id,
|
||||||
|
¶ms.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, ¶ms.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
36
source/blender/python/intern/bpy_manipulator_wrap.h
Normal file
36
source/blender/python/intern/bpy_manipulator_wrap.h
Normal file
@ -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__ */
|
||||||
|
|
@ -1839,19 +1839,28 @@ static int pyrna_py_to_prop(
|
|||||||
* class mixing if this causes problems in the future it should be removed.
|
* class mixing if this causes problems in the future it should be removed.
|
||||||
*/
|
*/
|
||||||
if ((ptr_type == &RNA_AnyType) &&
|
if ((ptr_type == &RNA_AnyType) &&
|
||||||
(BPy_StructRNA_Check(value)) &&
|
(BPy_StructRNA_Check(value)))
|
||||||
(RNA_struct_is_a(((BPy_StructRNA *)value)->ptr.type, &RNA_Operator)))
|
|
||||||
{
|
{
|
||||||
value = PyObject_GetAttr(value, bpy_intern_str_properties);
|
const StructRNA *base_type =
|
||||||
value_new = value;
|
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/ManipulatorProperties pointer and value is a map,
|
||||||
/* if property is an OperatorProperties pointer and value is a map,
|
|
||||||
* forward back to pyrna_pydict_to_props */
|
* forward back to pyrna_pydict_to_props */
|
||||||
if (RNA_struct_is_a(ptr_type, &RNA_OperatorProperties) && PyDict_Check(value)) {
|
if (PyDict_Check(value)) {
|
||||||
PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
|
const StructRNA *base_type = RNA_struct_base_child_of(ptr_type, NULL);
|
||||||
return pyrna_pydict_to_props(&opptr, value, false, error_prefix);
|
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 */
|
/* 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 = itemptr.data;
|
||||||
StructRNA *srna_base = RNA_struct_base(itemptr.data);
|
StructRNA *srna_base = RNA_struct_base(itemptr.data);
|
||||||
/* skip own operators, these double up [#29666] */
|
/* skip own operators, these double up [#29666] */
|
||||||
if (srna_base == &RNA_Operator) {
|
if (ELEM(srna_base, &RNA_Operator, &RNA_Manipulator)) {
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -7456,7 +7465,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
|
|||||||
PyGILState_STATE gilstate;
|
PyGILState_STATE gilstate;
|
||||||
|
|
||||||
#ifdef USE_PEDANTIC_WRITE
|
#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 */
|
// const char *func_id = RNA_function_identifier(func); /* UNUSED */
|
||||||
/* testing, for correctness, not operator and not draw function */
|
/* testing, for correctness, not operator and not draw function */
|
||||||
const bool is_readonly = !(RNA_function_flag(func) & FUNC_ALLOW_WRITE);
|
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) {
|
if (py_class->tp_init) {
|
||||||
#ifdef USE_PEDANTIC_WRITE
|
#ifdef USE_PEDANTIC_WRITE
|
||||||
const int prev_write = rna_disallow_writes;
|
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
|
#endif
|
||||||
|
|
||||||
/* true in most cases even when the class its self doesn't define an __init__ function. */
|
/* true in most cases even when the class its self doesn't define an __init__ function. */
|
||||||
|
341
source/blender/python/intern/bpy_rna_manipulator.c
Normal file
341
source/blender/python/intern/bpy_rna_manipulator.c
Normal file
@ -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,
|
||||||
|
¶ms.self,
|
||||||
|
¶ms.target,
|
||||||
|
¶ms.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_GET],
|
||||||
|
¶ms.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_SET],
|
||||||
|
¶ms.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
32
source/blender/python/intern/bpy_rna_manipulator.h
Normal file
32
source/blender/python/intern/bpy_rna_manipulator.h
Normal file
@ -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__ */
|
@ -133,6 +133,7 @@ struct wmOperator;
|
|||||||
struct wmOperatorType;
|
struct wmOperatorType;
|
||||||
struct wmWindow;
|
struct wmWindow;
|
||||||
struct wmWindowManager;
|
struct wmWindowManager;
|
||||||
|
struct wmManipulatorGroupType;
|
||||||
struct wmManipulatorMap;
|
struct wmManipulatorMap;
|
||||||
|
|
||||||
|
|
||||||
@ -164,6 +165,7 @@ struct wmManipulatorMap;
|
|||||||
#include "../blender/editors/include/ED_keyframes_edit.h"
|
#include "../blender/editors/include/ED_keyframes_edit.h"
|
||||||
#include "../blender/editors/include/ED_keyframing.h"
|
#include "../blender/editors/include/ED_keyframing.h"
|
||||||
#include "../blender/editors/include/ED_lattice.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_mball.h"
|
||||||
#include "../blender/editors/include/ED_mesh.h"
|
#include "../blender/editors/include/ED_mesh.h"
|
||||||
#include "../blender/editors/include/ED_node.h"
|
#include "../blender/editors/include/ED_node.h"
|
||||||
@ -186,6 +188,7 @@ struct wmManipulatorMap;
|
|||||||
#include "../blender/gpu/GPU_immediate.h"
|
#include "../blender/gpu/GPU_immediate.h"
|
||||||
#include "../blender/gpu/GPU_matrix.h"
|
#include "../blender/gpu/GPU_matrix.h"
|
||||||
#include "../blender/python/BPY_extern.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_engine.h"
|
||||||
#include "../blender/render/extern/include/RE_pipeline.h"
|
#include "../blender/render/extern/include/RE_pipeline.h"
|
||||||
#include "../blender/render/extern/include/RE_render_ext.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_jobs_start(struct wmWindowManager *wm, struct wmJob *job) RET_NONE
|
||||||
void WM_report(ReportType type, const char *message) 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_find(const struct wmManipulatorMapType_Params *wmap_params) RET_NULL
|
||||||
struct wmManipulatorMapType *WM_manipulatormaptype_ensure(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
|
struct wmManipulatorMap *WM_manipulatormap_new_from_type(const struct wmManipulatorMapType_Params *wmap_params) RET_NULL
|
||||||
|
Loading…
Reference in New Issue
Block a user