Merge branch 'master' into 28
[blender.git] / release / scripts / startup / bl_ui / properties_data_curve.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20 import bpy
21 from bpy.types import Panel
22 from rna_prop_ui import PropertyPanel
23
24 from bpy.types import Curve, SurfaceCurve, TextCurve
25
26
27 class CurveButtonsPanel:
28     bl_space_type = 'PROPERTIES'
29     bl_region_type = 'WINDOW'
30     bl_context = "data"
31
32     @classmethod
33     def poll(cls, context):
34         return (context.curve is not None)
35
36
37 class CurveButtonsPanelCurve(CurveButtonsPanel):
38     @classmethod
39     def poll(cls, context):
40         return (type(context.curve) is Curve)
41
42
43 class CurveButtonsPanelSurface(CurveButtonsPanel):
44     @classmethod
45     def poll(cls, context):
46         return (type(context.curve) is SurfaceCurve)
47
48
49 class CurveButtonsPanelText(CurveButtonsPanel):
50     @classmethod
51     def poll(cls, context):
52         return (type(context.curve) is TextCurve)
53
54
55 class CurveButtonsPanelActive(CurveButtonsPanel):
56     """Same as above but for curves only"""
57
58     @classmethod
59     def poll(cls, context):
60         curve = context.curve
61         return (curve and type(curve) is not TextCurve and curve.splines.active)
62
63
64 class DATA_PT_context_curve(CurveButtonsPanel, Panel):
65     bl_label = ""
66     bl_options = {'HIDE_HEADER'}
67
68     def draw(self, context):
69         layout = self.layout
70
71         obj = context.object
72         curve = context.curve
73         space = context.space_data
74
75         if obj:
76             layout.template_ID(obj, "data")
77         elif curve:
78             layout.template_ID(space, "pin_id")
79
80
81 class DATA_PT_shape_curve(CurveButtonsPanel, Panel):
82     bl_label = "Shape"
83
84     def draw(self, context):
85         layout = self.layout
86
87         curve = context.curve
88         is_surf = type(curve) is SurfaceCurve
89         is_curve = type(curve) is Curve
90         is_text = type(curve) is TextCurve
91
92         if is_curve:
93             row = layout.row()
94             row.prop(curve, "dimensions", expand=True)
95
96         layout.use_property_split = True
97
98         col = layout.column()
99         sub = col.column(align=True)
100         sub.prop(curve, "resolution_u", text="Resolution Preview U")
101         if is_surf:
102             sub.prop(curve, "resolution_v", text="V")
103
104         sub = col.column(align=True)
105         sub.prop(curve, "render_resolution_u", text="Render U")
106         if is_surf:
107             sub.prop(curve, "render_resolution_v", text="V")
108         col.separator()
109
110         if is_curve:
111             col.prop(curve, "twist_mode")
112             col.prop(curve, "twist_smooth", text="Smooth")
113         elif is_text:
114             col.prop(curve, "use_fast_edit", text="Fast Editing")
115
116         if is_curve or is_text:
117             col = layout.column()
118             col.separator()
119
120             sub = col.column()
121             sub.active = (curve.dimensions == '2D' or (curve.bevel_object is None and curve.dimensions == '3D'))
122             sub.prop(curve, "fill_mode")
123             col.prop(curve, "use_fill_deform")
124
125         if is_curve:
126             col = layout.column()
127             col.separator()
128
129             sub = col.column()
130             sub.prop(curve, "use_radius")
131             sub.prop(curve, "use_stretch")
132             sub.prop(curve, "use_deform_bounds")
133
134
135 class DATA_PT_curve_texture_space(CurveButtonsPanel, Panel):
136     bl_label = "Texture Space"
137     bl_options = {'DEFAULT_CLOSED'}
138     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
139
140     def draw(self, context):
141         layout = self.layout
142         layout.use_property_split = True
143
144         curve = context.curve
145
146         col = layout.column()
147         col.prop(curve, "use_uv_as_generated")
148         col.prop(curve, "use_auto_texspace")
149
150         col = layout.column()
151         col.prop(curve, "texspace_location")
152         col.prop(curve, "texspace_size")
153
154         layout.operator("curve.match_texture_space")
155
156
157 class DATA_PT_geometry_curve(CurveButtonsPanelCurve, Panel):
158     bl_label = "Geometry"
159
160     @classmethod
161     def poll(cls, context):
162         return (type(context.curve) in {Curve, TextCurve})
163
164     def draw(self, context):
165         layout = self.layout
166         layout.use_property_split = True
167
168         curve = context.curve
169
170         col = layout.column()
171         col.prop(curve, "offset")
172
173         sub = col.column()
174         sub.active = (curve.bevel_object is None)
175         sub.prop(curve, "extrude")
176
177         col.prop(curve, "taper_object")
178
179         sub = col.column()
180         sub.active = curve.taper_object is not None
181         sub.prop(curve, "use_map_taper")
182
183
184 class DATA_PT_geometry_curve_bevel(CurveButtonsPanelCurve, Panel):
185     bl_label = "Bevel"
186     bl_parent_id = "DATA_PT_geometry_curve"
187
188     @classmethod
189     def poll(cls, context):
190         return (type(context.curve) in {Curve, TextCurve})
191
192     def draw(self, context):
193         layout = self.layout
194         layout.use_property_split = True
195
196         curve = context.curve
197
198         col = layout.column()
199         sub = col.column()
200         sub.active = (curve.bevel_object is None)
201         sub.prop(curve, "bevel_depth", text="Depth")
202         sub.prop(curve, "bevel_resolution", text="Resolution")
203
204         col.prop(curve, "bevel_object", text="Object")
205
206         sub = col.column()
207         sub.active = curve.bevel_object is not None
208         sub.prop(curve, "use_fill_caps")
209
210         if type(curve) is not TextCurve:
211
212             col = layout.column()
213             col.active = (
214                 (curve.bevel_depth > 0.0) or
215                 (curve.extrude > 0.0) or
216                 (curve.bevel_object is not None)
217             )
218             sub = col.column(align=True)
219             sub.prop(curve, "bevel_factor_start", text="Bevel Start")
220             sub.prop(curve, "bevel_factor_end", text="End")
221
222             sub = col.column(align=True)
223             sub.prop(curve, "bevel_factor_mapping_start", text="Bevel Mapping Start")
224             sub.prop(curve, "bevel_factor_mapping_end", text="End")
225
226
227 class DATA_PT_pathanim(CurveButtonsPanelCurve, Panel):
228     bl_label = "Path Animation"
229
230     def draw_header(self, context):
231         curve = context.curve
232
233         self.layout.prop(curve, "use_path", text="")
234
235     def draw(self, context):
236         layout = self.layout
237         layout.use_property_split = True
238
239         curve = context.curve
240
241         layout.active = curve.use_path
242
243         col = layout.column()
244         col.prop(curve, "path_duration", text="Frames")
245         col.prop(curve, "eval_time")
246
247         # these are for paths only
248         col.separator()
249
250         col.prop(curve, "use_path_follow")
251
252
253 class DATA_PT_active_spline(CurveButtonsPanelActive, Panel):
254     bl_label = "Active Spline"
255
256     def draw(self, context):
257         layout = self.layout
258         layout.use_property_split = True
259
260         curve = context.curve
261         act_spline = curve.splines.active
262         is_surf = type(curve) is SurfaceCurve
263         is_poly = (act_spline.type == 'POLY')
264
265         col = layout.column()
266
267         if is_poly:
268             # These settings are below but its easier to have
269             # polys set aside since they use so few settings
270
271             col.prop(act_spline, "use_cyclic_u")
272             col.prop(act_spline, "use_smooth")
273         else:
274
275             sub = col.column(align=True)
276             sub.prop(act_spline, "use_cyclic_u")
277             if is_surf:
278                 sub.prop(act_spline, "use_cyclic_v", text="V")
279
280             if act_spline.type == 'NURBS':
281                 sub = col.column(align=True)
282                 # sub.active = (not act_spline.use_cyclic_u)
283                 sub.prop(act_spline, "use_bezier_u", text="Bezier U")
284
285                 if is_surf:
286                     subsub = sub.column()
287                     subsub.active = (not act_spline.use_cyclic_v)
288                     subsub.prop(act_spline, "use_bezier_v", text="V")
289
290                 sub = col.column(align=True)
291                 sub.prop(act_spline, "use_endpoint_u", text="Endpoint U")
292
293                 if is_surf:
294                     subsub = sub.column()
295                     subsub.active = (not act_spline.use_cyclic_v)
296                     subsub.prop(act_spline, "use_endpoint_v", text="V")
297
298                 sub = col.column(align=True)
299                 sub.prop(act_spline, "order_u", text="Order U")
300
301                 if is_surf:
302                     sub.prop(act_spline, "order_v", text="V")
303
304             sub = col.column(align=True)
305             sub.prop(act_spline, "resolution_u", text="Resolution U")
306             if is_surf:
307                 sub.prop(act_spline, "resolution_v", text="V")
308
309             if act_spline.type == 'BEZIER':
310
311                 col.separator()
312
313                 sub = col.column()
314                 sub.active = (curve.dimensions == '3D')
315                 sub.prop(act_spline, "tilt_interpolation", text="Interpolation Tilt")
316
317                 col.prop(act_spline, "radius_interpolation", text="Radius")
318
319             layout.prop(act_spline, "use_smooth")
320
321
322 class DATA_PT_font(CurveButtonsPanelText, Panel):
323     bl_label = "Font"
324
325     def draw(self, context):
326         layout = self.layout
327
328         text = context.curve
329         char = context.curve.edit_format
330
331         row = layout.split(percentage=0.25)
332         row.label(text="Regular")
333         row.template_ID(text, "font", open="font.open", unlink="font.unlink")
334         row = layout.split(percentage=0.25)
335         row.label(text="Bold")
336         row.template_ID(text, "font_bold", open="font.open", unlink="font.unlink")
337         row = layout.split(percentage=0.25)
338         row.label(text="Italic")
339         row.template_ID(text, "font_italic", open="font.open", unlink="font.unlink")
340         row = layout.split(percentage=0.25)
341         row.label(text="Bold & Italic")
342         row.template_ID(text, "font_bold_italic", open="font.open", unlink="font.unlink")
343
344         layout.separator()
345
346         row = layout.row(align=True)
347         row.prop(char, "use_bold", toggle=True)
348         row.prop(char, "use_italic", toggle=True)
349         row.prop(char, "use_underline", toggle=True)
350         row.prop(char, "use_small_caps", toggle=True)
351
352
353 class DATA_PT_font_transform(CurveButtonsPanelText, Panel):
354     bl_label = "Transform"
355     bl_parent_id = "DATA_PT_font"
356
357     def draw(self, context):
358         layout = self.layout
359
360         text = context.curve
361         char = context.curve.edit_format
362
363         layout.use_property_split = True
364
365         col = layout.column()
366
367         col.separator()
368
369         col.prop(text, "size", text="Size")
370         col.prop(text, "shear")
371
372         col.separator()
373
374         col.prop(text, "family")
375         col.prop(text, "follow_curve")
376
377         col.separator()
378
379         sub = col.column(align=True)
380         sub.prop(text, "underline_position", text="Underline Position")
381         sub.prop(text, "underline_height", text="Underline Thickness")
382
383         col.prop(text, "small_caps_scale", text="Small Caps Scale")
384
385
386 class DATA_PT_paragraph(CurveButtonsPanelText, Panel):
387     bl_label = "Paragraph"
388
389     def draw(self, context):
390         layout = self.layout
391
392         text = context.curve
393
394
395 class DATA_PT_paragraph_alignment(CurveButtonsPanelText, Panel):
396     bl_parent_id = "DATA_PT_paragraph"
397     bl_label = "Alignment"
398
399     def draw(self, context):
400         layout = self.layout
401         layout.use_property_split = False
402
403         text = context.curve
404
405         layout.row().prop(text, "align_x", expand=True)
406         layout.row().prop(text, "align_y", expand=True)
407
408
409 class DATA_PT_paragraph_spacing(CurveButtonsPanelText, Panel):
410     bl_parent_id = "DATA_PT_paragraph"
411     bl_label = "Spacing"
412
413     def draw(self, context):
414         layout = self.layout
415         layout.use_property_split = True
416
417         text = context.curve
418
419         col = layout.column(align=True)
420         col.prop(text, "space_character", text="Character Spacing")
421         col.prop(text, "space_word", text="Word Spacing")
422         col.prop(text, "space_line", text="Line Spacing")
423
424         layout.separator()
425
426         col = layout.column(align=True)
427         col.prop(text, "offset_x", text="Offset X")
428         col.prop(text, "offset_y", text="Y")
429
430
431 class DATA_PT_text_boxes(CurveButtonsPanelText, Panel):
432     bl_label = "Text Boxes"
433
434     def draw(self, context):
435         layout = self.layout
436
437         text = context.curve
438
439         layout.operator("font.textbox_add", icon='ZOOMIN')
440
441         for i, box in enumerate(text.text_boxes):
442
443             boxy = layout.box()
444
445             row = boxy.row()
446
447             col = row.column()
448             col.use_property_split = True
449
450             sub = col.column(align=True)
451             sub.prop(box, "width", text="Size X")
452             sub.prop(box, "height", text="Y")
453
454             sub = col.column(align=True)
455             sub.prop(box, "x", text="Offset X")
456             sub.prop(box, "y", text="Y")
457
458             row.operator("font.textbox_remove", text="", icon='X', emboss=False).index = i
459
460
461 class DATA_PT_custom_props_curve(CurveButtonsPanel, PropertyPanel, Panel):
462     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
463     _context_path = "object.data"
464     _property_type = bpy.types.Curve
465
466
467 classes = (
468     DATA_PT_context_curve,
469     DATA_PT_shape_curve,
470     DATA_PT_curve_texture_space,
471     DATA_PT_geometry_curve,
472     DATA_PT_geometry_curve_bevel,
473     DATA_PT_pathanim,
474     DATA_PT_active_spline,
475     DATA_PT_font,
476     DATA_PT_font_transform,
477     DATA_PT_paragraph,
478     DATA_PT_paragraph_alignment,
479     DATA_PT_paragraph_spacing,
480     DATA_PT_text_boxes,
481     DATA_PT_custom_props_curve,
482 )
483
484 if __name__ == "__main__":  # only for live edit.
485     from bpy.utils import register_class
486     for cls in classes:
487         register_class(cls)