Workspace: Move engines to workspace and Properties Editor cleanup
[blender.git] / release / scripts / templates_py / manipulator_custom_geometry.py
1 # Example of a custom widget that defines it's own geometry.
2 #
3 # Usage: Select a lamp in the 3D view and drag the arrow at it's rear
4 # to change it's energy value.
5 #
6 import bpy
7 from bpy.types import (
8     Manipulator,
9     ManipulatorGroup,
10 )
11
12 # Coordinates (each one is a triangle).
13 custom_shape_verts = (
14     (3.0, 1.0, -1.0), (2.0, 2.0, -1.0), (3.0, 3.0, -1.0),
15     (1.0, 3.0, 1.0), (3.0, 3.0, -1.0), (1.0, 3.0, -1.0),
16     (3.0, 3.0, 1.0), (3.0, 1.0, -1.0), (3.0, 3.0, -1.0),
17     (2.0, 0.0, 1.0), (3.0, 1.0, -1.0), (3.0, 1.0, 1.0),
18     (2.0, 0.0, -1.0), (2.0, 2.0, 1.0), (2.0, 2.0, -1.0),
19     (2.0, 2.0, -1.0), (0.0, 2.0, 1.0), (0.0, 2.0, -1.0),
20     (1.0, 3.0, 1.0), (2.0, 2.0, 1.0), (3.0, 3.0, 1.0),
21     (0.0, 2.0, -1.0), (1.0, 3.0, 1.0), (1.0, 3.0, -1.0),
22     (2.0, 2.0, 1.0), (3.0, 1.0, 1.0), (3.0, 3.0, 1.0),
23     (2.0, 2.0, -1.0), (1.0, 3.0, -1.0), (3.0, 3.0, -1.0),
24     (-3.0, -1.0, -1.0), (-2.0, -2.0, -1.0), (-3.0, -3.0, -1.0),
25     (-1.0, -3.0, 1.0), (-3.0, -3.0, -1.0), (-1.0, -3.0, -1.0),
26     (-3.0, -3.0, 1.0), (-3.0, -1.0, -1.0), (-3.0, -3.0, -1.0),
27     (-2.0, 0.0, 1.0), (-3.0, -1.0, -1.0), (-3.0, -1.0, 1.0),
28     (-2.0, 0.0, -1.0), (-2.0, -2.0, 1.0), (-2.0, -2.0, -1.0),
29     (-2.0, -2.0, -1.0), (0.0, -2.0, 1.0), (0.0, -2.0, -1.0),
30     (-1.0, -3.0, 1.0), (-2.0, -2.0, 1.0), (-3.0, -3.0, 1.0),
31     (0.0, -2.0, -1.0), (-1.0, -3.0, 1.0), (-1.0, -3.0, -1.0),
32     (-2.0, -2.0, 1.0), (-3.0, -1.0, 1.0), (-3.0, -3.0, 1.0),
33     (-2.0, -2.0, -1.0), (-1.0, -3.0, -1.0), (-3.0, -3.0, -1.0),
34     (1.0, -1.0, 0.0), (-1.0, -1.0, 0.0), (0.0, 0.0, -5.0),
35     (-1.0, -1.0, 0.0), (1.0, -1.0, 0.0), (0.0, 0.0, 5.0),
36     (1.0, -1.0, 0.0), (1.0, 1.0, 0.0), (0.0, 0.0, 5.0),
37     (1.0, 1.0, 0.0), (-1.0, 1.0, 0.0), (0.0, 0.0, 5.0),
38     (-1.0, 1.0, 0.0), (-1.0, -1.0, 0.0), (0.0, 0.0, 5.0),
39     (-1.0, -1.0, 0.0), (-1.0, 1.0, 0.0), (0.0, 0.0, -5.0),
40     (-1.0, 1.0, 0.0), (1.0, 1.0, 0.0), (0.0, 0.0, -5.0),
41     (1.0, 1.0, 0.0), (1.0, -1.0, 0.0), (0.0, 0.0, -5.0),
42     (3.0, 1.0, -1.0), (2.0, 0.0, -1.0), (2.0, 2.0, -1.0),
43     (1.0, 3.0, 1.0), (3.0, 3.0, 1.0), (3.0, 3.0, -1.0),
44     (3.0, 3.0, 1.0), (3.0, 1.0, 1.0), (3.0, 1.0, -1.0),
45     (2.0, 0.0, 1.0), (2.0, 0.0, -1.0), (3.0, 1.0, -1.0),
46     (2.0, 0.0, -1.0), (2.0, 0.0, 1.0), (2.0, 2.0, 1.0),
47     (2.0, 2.0, -1.0), (2.0, 2.0, 1.0), (0.0, 2.0, 1.0),
48     (1.0, 3.0, 1.0), (0.0, 2.0, 1.0), (2.0, 2.0, 1.0),
49     (0.0, 2.0, -1.0), (0.0, 2.0, 1.0), (1.0, 3.0, 1.0),
50     (2.0, 2.0, 1.0), (2.0, 0.0, 1.0), (3.0, 1.0, 1.0),
51     (2.0, 2.0, -1.0), (0.0, 2.0, -1.0), (1.0, 3.0, -1.0),
52     (-3.0, -1.0, -1.0), (-2.0, 0.0, -1.0), (-2.0, -2.0, -1.0),
53     (-1.0, -3.0, 1.0), (-3.0, -3.0, 1.0), (-3.0, -3.0, -1.0),
54     (-3.0, -3.0, 1.0), (-3.0, -1.0, 1.0), (-3.0, -1.0, -1.0),
55     (-2.0, 0.0, 1.0), (-2.0, 0.0, -1.0), (-3.0, -1.0, -1.0),
56     (-2.0, 0.0, -1.0), (-2.0, 0.0, 1.0), (-2.0, -2.0, 1.0),
57     (-2.0, -2.0, -1.0), (-2.0, -2.0, 1.0), (0.0, -2.0, 1.0),
58     (-1.0, -3.0, 1.0), (0.0, -2.0, 1.0), (-2.0, -2.0, 1.0),
59     (0.0, -2.0, -1.0), (0.0, -2.0, 1.0), (-1.0, -3.0, 1.0),
60     (-2.0, -2.0, 1.0), (-2.0, 0.0, 1.0), (-3.0, -1.0, 1.0),
61     (-2.0, -2.0, -1.0), (0.0, -2.0, -1.0), (-1.0, -3.0, -1.0),
62 )
63
64
65 class MyCustomShapeWidget(Manipulator):
66     bl_idname = "VIEW3D_WT_auto_facemap"
67     bl_target_properties = (
68         {"id": "offset", "type": 'FLOAT', "array_length": 1},
69     )
70
71     __slots__ = (
72         "custom_shape",
73         "init_mouse_y",
74         "init_value",
75     )
76
77     def _update_offset_matrix(self):
78         # offset behind the lamp
79         self.matrix_offset.col[3][2] = self.target_get_value("offset") / -10.0
80
81     def draw(self, context):
82         self._update_offset_matrix()
83         self.draw_custom_shape(self.custom_shape)
84
85     def draw_select(self, context, select_id):
86         self._update_offset_matrix()
87         self.draw_custom_shape(self.custom_shape, select_id=select_id)
88
89     def setup(self):
90         if not hasattr(self, "custom_shape"):
91             self.custom_shape = self.new_custom_shape('TRIS', custom_shape_verts)
92
93     def invoke(self, context, event):
94         self.init_mouse_y = event.mouse_y
95         self.init_value = self.target_get_value("offset")
96         return {'RUNNING_MODAL'}
97
98     def exit(self, context, cancel):
99         context.area.header_text_set()
100         if cancel:
101             self.target_set_value("offset", self.init_value)
102
103     def modal(self, context, event, tweak):
104         delta = (event.mouse_y - self.init_mouse_y) / 10.0
105         if 'SNAP' in tweak:
106             delta = round(delta)
107         if 'PRECISE' in tweak:
108             delta /= 10.0
109         value = self.init_value + delta
110         self.target_set_value("offset", value)
111         context.area.header_text_set("My Manipulator: %.4f" % value)
112         return {'RUNNING_MODAL'}
113
114
115 class MyCustomShapeWidgetGroup(ManipulatorGroup):
116     bl_idname = "OBJECT_WGT_lamp_test"
117     bl_label = "Test Lamp Widget"
118     bl_space_type = 'VIEW_3D'
119     bl_region_type = 'WINDOW'
120     bl_options = {'3D', 'PERSISTENT'}
121
122     @classmethod
123     def poll(cls, context):
124         ob = context.object
125         return (ob and ob.type == 'LAMP')
126
127     def setup(self, context):
128         # Assign the 'offset' target property to the lamp energy.
129         ob = context.object
130         mpr = self.manipulators.new(MyCustomShapeWidget.bl_idname)
131         mpr.target_set_prop("offset", ob.data, "energy")
132         mpr.matrix_basis = ob.matrix_world.normalized()
133
134         mpr.color = 1.0, 0.5, 1.0
135         mpr.alpha = 0.5
136
137         mpr.color_highlight = 1.0, 0.5, 1.0
138         mpr.alpha_highlight = 0.5
139
140         # units are large, so shrink to something more reasonable.
141         mpr.scale_basis = 0.1
142         mpr.use_draw_modal = True
143
144         self.energy_widget = mpr
145
146     def refresh(self, context):
147         ob = context.object
148         mpr = self.energy_widget
149         mpr.matrix_basis = ob.matrix_world.normalized()
150
151
152 classes = (
153     MyCustomShapeWidget,
154     MyCustomShapeWidgetGroup,
155 )
156
157 for cls in classes:
158     bpy.utils.register_class(cls)