UI: Add missing UV tools in the UV/Image Editor Window > Tools tab
[blender.git] / release / scripts / startup / bl_ui / space_image.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 import math
22 from bpy.types import Header, Menu, Panel
23 from bl_ui.properties_paint_common import (
24         UnifiedPaintPanel,
25         brush_texture_settings,
26         brush_texpaint_common,
27         brush_mask_texture_settings,
28         )
29 from bl_ui.properties_grease_pencil_common import (
30         GreasePencilDrawingToolsPanel,
31         GreasePencilStrokeEditPanel,
32         GreasePencilStrokeSculptPanel,
33         GreasePencilBrushPanel,
34         GreasePencilBrushCurvesPanel,
35         GreasePencilDataPanel,
36         GreasePencilPaletteColorPanel
37         )
38 from bpy.app.translations import pgettext_iface as iface_
39
40
41 class ImagePaintPanel(UnifiedPaintPanel):
42     bl_space_type = 'IMAGE_EDITOR'
43     bl_region_type = 'TOOLS'
44
45
46 class BrushButtonsPanel(UnifiedPaintPanel):
47     bl_space_type = 'IMAGE_EDITOR'
48     bl_region_type = 'TOOLS'
49
50     @classmethod
51     def poll(cls, context):
52         sima = context.space_data
53         toolsettings = context.tool_settings.image_paint
54         return sima.show_paint and toolsettings.brush
55
56
57 class UVToolsPanel:
58     bl_space_type = 'IMAGE_EDITOR'
59     bl_region_type = 'TOOLS'
60     bl_category = "Tools"
61
62     @classmethod
63     def poll(cls, context):
64         sima = context.space_data
65         return sima.show_uvedit and not context.tool_settings.use_uv_sculpt
66
67
68 class IMAGE_MT_view(Menu):
69     bl_label = "View"
70
71     def draw(self, context):
72         layout = self.layout
73
74         sima = context.space_data
75         uv = sima.uv_editor
76         toolsettings = context.tool_settings
77         paint = toolsettings.image_paint
78
79         show_uvedit = sima.show_uvedit
80         show_render = sima.show_render
81
82         layout.operator("image.properties", icon='MENU_PANEL')
83         layout.operator("image.toolshelf", icon='MENU_PANEL')
84
85         layout.separator()
86
87         layout.prop(sima, "use_realtime_update")
88         if show_uvedit:
89             layout.prop(toolsettings, "show_uv_local_view")
90
91         layout.prop(uv, "show_other_objects")
92         layout.prop(uv, "show_metadata")
93         if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'):
94             layout.prop(uv, "show_texpaint")
95             layout.prop(toolsettings, "show_uv_local_view", text="Show Same Material")
96
97         layout.separator()
98
99         layout.operator("image.view_zoom_in")
100         layout.operator("image.view_zoom_out")
101
102         layout.separator()
103
104         ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
105
106         for a, b in ratios:
107             layout.operator("image.view_zoom_ratio", text=iface_("Zoom %d:%d") % (a, b), translate=False).ratio = a / b
108
109         layout.separator()
110
111         if show_uvedit:
112             layout.operator("image.view_selected")
113
114         layout.operator("image.view_all")
115         layout.operator("image.view_all", text="View Fit").fit_view = True
116
117         layout.separator()
118
119         if show_render:
120             layout.operator("image.render_border")
121             layout.operator("image.clear_render_border")
122
123             layout.separator()
124
125             layout.operator("image.cycle_render_slot", text="Render Slot Cycle Next")
126             layout.operator("image.cycle_render_slot", text="Render Slot Cycle Previous").reverse = True
127             layout.separator()
128
129         layout.operator("screen.area_dupli")
130         layout.operator("screen.screen_full_area")
131         layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True
132
133
134 class IMAGE_MT_select(Menu):
135     bl_label = "Select"
136
137     def draw(self, context):
138         layout = self.layout
139
140         layout.operator("uv.select_border").pinned = False
141         layout.operator("uv.select_border", text="Border Select Pinned").pinned = True
142         layout.operator("uv.circle_select")
143
144         layout.separator()
145
146         layout.operator("uv.select_all").action = 'TOGGLE'
147         layout.operator("uv.select_all", text="Inverse").action = 'INVERT'
148
149         layout.separator()
150
151         layout.operator("uv.select_pinned")
152         layout.operator("uv.select_linked").extend = False
153
154         layout.separator()
155
156         layout.operator("uv.select_less", text="Less")
157         layout.operator("uv.select_more", text="More")
158
159         layout.separator()
160
161         layout.operator("uv.select_split")
162
163
164 class IMAGE_MT_brush(Menu):
165     bl_label = "Brush"
166
167     def draw(self, context):
168         layout = self.layout
169         toolsettings = context.tool_settings
170         settings = toolsettings.image_paint
171         brush = settings.brush
172
173         ups = context.tool_settings.unified_paint_settings
174         layout.prop(ups, "use_unified_size", text="Unified Size")
175         layout.prop(ups, "use_unified_strength", text="Unified Strength")
176         layout.prop(ups, "use_unified_color", text="Unified Color")
177         layout.separator()
178
179         # brush tool
180         layout.prop_menu_enum(brush, "image_tool")
181
182
183 class IMAGE_MT_image(Menu):
184     bl_label = "Image"
185
186     def draw(self, context):
187         layout = self.layout
188
189         sima = context.space_data
190         ima = sima.image
191
192         layout.operator("image.new")
193         layout.operator("image.open")
194
195         show_render = sima.show_render
196
197         layout.operator("image.read_renderlayers")
198
199         layout.operator("image.save_dirty", text="Save All Images")
200
201         if ima:
202             if not show_render:
203                 layout.operator("image.replace")
204                 layout.operator("image.reload")
205
206             layout.operator("image.save")
207             layout.operator("image.save_as")
208             layout.operator("image.save_as", text="Save a Copy").copy = True
209
210             if ima.source == 'SEQUENCE':
211                 layout.operator("image.save_sequence")
212
213             layout.operator("image.external_edit", "Edit Externally")
214
215             layout.separator()
216
217             layout.menu("IMAGE_MT_image_invert")
218
219             if not show_render:
220                 if not ima.packed_file:
221                     layout.separator()
222                     layout.operator("image.pack")
223
224                 # only for dirty && specific image types, perhaps
225                 # this could be done in operator poll too
226                 if ima.is_dirty:
227                     if ima.source in {'FILE', 'GENERATED'} and ima.type != 'OPEN_EXR_MULTILAYER':
228                         if ima.packed_file:
229                             layout.separator()
230                         layout.operator("image.pack", text="Pack As PNG").as_png = True
231
232
233 class IMAGE_MT_image_invert(Menu):
234     bl_label = "Invert"
235
236     def draw(self, context):
237         layout = self.layout
238
239         props = layout.operator("image.invert", text="Invert Image Colors")
240         props.invert_r = True
241         props.invert_g = True
242         props.invert_b = True
243
244         layout.separator()
245
246         layout.operator("image.invert", text="Invert Red Channel").invert_r = True
247         layout.operator("image.invert", text="Invert Green Channel").invert_g = True
248         layout.operator("image.invert", text="Invert Blue Channel").invert_b = True
249         layout.operator("image.invert", text="Invert Alpha Channel").invert_a = True
250
251
252 class IMAGE_MT_uvs_showhide(Menu):
253     bl_label = "Show/Hide Faces"
254
255     def draw(self, context):
256         layout = self.layout
257
258         layout.operator("uv.reveal")
259         layout.operator("uv.hide", text="Hide Selected").unselected = False
260         layout.operator("uv.hide", text="Hide Unselected").unselected = True
261
262
263 class IMAGE_MT_uvs_proportional(Menu):
264     bl_label = "Proportional Editing"
265
266     def draw(self, context):
267         layout = self.layout
268
269         layout.props_enum(context.tool_settings, "proportional_edit")
270
271         layout.separator()
272
273         layout.label("Falloff:")
274         layout.props_enum(context.tool_settings, "proportional_edit_falloff")
275
276
277 class IMAGE_MT_uvs_transform(Menu):
278     bl_label = "Transform"
279
280     def draw(self, context):
281         layout = self.layout
282
283         layout.operator("transform.translate")
284         layout.operator("transform.rotate")
285         layout.operator("transform.resize")
286
287         layout.separator()
288
289         layout.operator("transform.shear")
290
291
292 class IMAGE_MT_uvs_snap(Menu):
293     bl_label = "Snap"
294
295     def draw(self, context):
296         layout = self.layout
297
298         layout.operator_context = 'EXEC_REGION_WIN'
299
300         layout.operator("uv.snap_selected", text="Selected to Pixels").target = 'PIXELS'
301         layout.operator("uv.snap_selected", text="Selected to Cursor").target = 'CURSOR'
302         layout.operator("uv.snap_selected", text="Selected to Cursor (Offset)").target = 'CURSOR_OFFSET'
303         layout.operator("uv.snap_selected", text="Selected to Adjacent Unselected").target = 'ADJACENT_UNSELECTED'
304
305         layout.separator()
306
307         layout.operator("uv.snap_cursor", text="Cursor to Pixels").target = 'PIXELS'
308         layout.operator("uv.snap_cursor", text="Cursor to Selected").target = 'SELECTED'
309
310
311 class IMAGE_MT_uvs_mirror(Menu):
312     bl_label = "Mirror"
313
314     def draw(self, context):
315         layout = self.layout
316
317         layout.operator_context = 'EXEC_REGION_WIN'
318
319         layout.operator("transform.mirror", text="X Axis").constraint_axis[0] = True
320         layout.operator("transform.mirror", text="Y Axis").constraint_axis[1] = True
321
322
323 class IMAGE_MT_uvs_weldalign(Menu):
324     bl_label = "Weld/Align"
325
326     def draw(self, context):
327         layout = self.layout
328
329         layout.operator("uv.weld")  # W, 1
330         layout.operator("uv.remove_doubles")
331         layout.operator_enum("uv.align", "axis")  # W, 2/3/4
332
333
334 class IMAGE_MT_uvs(Menu):
335     bl_label = "UVs"
336
337     def draw(self, context):
338         layout = self.layout
339
340         sima = context.space_data
341         uv = sima.uv_editor
342         toolsettings = context.tool_settings
343
344         layout.prop(uv, "use_snap_to_pixels")
345         layout.prop(uv, "lock_bounds")
346
347         layout.separator()
348
349         layout.prop(toolsettings, "use_uv_sculpt")
350
351         layout.separator()
352
353         layout.prop(uv, "use_live_unwrap")
354         layout.operator("uv.unwrap")
355         layout.operator("uv.pin", text="Unpin").clear = True
356         layout.operator("uv.pin").clear = False
357
358         layout.separator()
359
360         layout.operator("uv.pack_islands")
361         layout.operator("uv.average_islands_scale")
362         layout.operator("uv.minimize_stretch")
363         layout.operator("uv.stitch")
364         layout.operator("uv.mark_seam").clear = False
365         layout.operator("uv.mark_seam", text="Clear Seam").clear = True
366         layout.operator("uv.seams_from_islands")
367         layout.operator("mesh.faces_mirror_uv")
368
369         layout.separator()
370
371         layout.menu("IMAGE_MT_uvs_transform")
372         layout.menu("IMAGE_MT_uvs_mirror")
373         layout.menu("IMAGE_MT_uvs_snap")
374         layout.menu("IMAGE_MT_uvs_weldalign")
375
376         layout.separator()
377
378         layout.menu("IMAGE_MT_uvs_proportional")
379
380         layout.separator()
381
382         layout.menu("IMAGE_MT_uvs_showhide")
383
384
385 class IMAGE_MT_uvs_select_mode(Menu):
386     bl_label = "UV Select Mode"
387
388     def draw(self, context):
389         layout = self.layout
390
391         layout.operator_context = 'INVOKE_REGION_WIN'
392         toolsettings = context.tool_settings
393
394         # do smart things depending on whether uv_select_sync is on
395
396         if toolsettings.use_uv_select_sync:
397             props = layout.operator("wm.context_set_value", text="Vertex", icon='VERTEXSEL')
398             props.value = "(True, False, False)"
399             props.data_path = "tool_settings.mesh_select_mode"
400
401             props = layout.operator("wm.context_set_value", text="Edge", icon='EDGESEL')
402             props.value = "(False, True, False)"
403             props.data_path = "tool_settings.mesh_select_mode"
404
405             props = layout.operator("wm.context_set_value", text="Face", icon='FACESEL')
406             props.value = "(False, False, True)"
407             props.data_path = "tool_settings.mesh_select_mode"
408
409         else:
410             props = layout.operator("wm.context_set_string", text="Vertex", icon='UV_VERTEXSEL')
411             props.value = 'VERTEX'
412             props.data_path = "tool_settings.uv_select_mode"
413
414             props = layout.operator("wm.context_set_string", text="Edge", icon='UV_EDGESEL')
415             props.value = 'EDGE'
416             props.data_path = "tool_settings.uv_select_mode"
417
418             props = layout.operator("wm.context_set_string", text="Face", icon='UV_FACESEL')
419             props.value = 'FACE'
420             props.data_path = "tool_settings.uv_select_mode"
421
422             props = layout.operator("wm.context_set_string", text="Island", icon='UV_ISLANDSEL')
423             props.value = 'ISLAND'
424             props.data_path = "tool_settings.uv_select_mode"
425
426
427 class IMAGE_HT_header(Header):
428     bl_space_type = 'IMAGE_EDITOR'
429
430     def draw(self, context):
431         layout = self.layout
432
433         sima = context.space_data
434         ima = sima.image
435         iuser = sima.image_user
436         toolsettings = context.tool_settings
437         mode = sima.mode
438
439         show_render = sima.show_render
440         show_uvedit = sima.show_uvedit
441         show_maskedit = sima.show_maskedit
442
443         row = layout.row(align=True)
444         row.template_header()
445
446         MASK_MT_editor_menus.draw_collapsible(context, layout)
447
448         layout.template_ID(sima, "image", new="image.new", open="image.open")
449         if not show_render:
450             layout.prop(sima, "use_image_pin", text="")
451
452         layout.prop(sima, "mode", text="")
453
454         if show_maskedit:
455             row = layout.row()
456             row.template_ID(sima, "mask", new="mask.new")
457
458         layout.prop(sima, "pivot_point", icon_only=True)
459
460         # uv editing
461         if show_uvedit:
462             uvedit = sima.uv_editor
463
464             layout.prop(toolsettings, "use_uv_select_sync", text="")
465
466             if toolsettings.use_uv_select_sync:
467                 layout.template_edit_mode_selection()
468             else:
469                 layout.prop(toolsettings, "uv_select_mode", text="", expand=True)
470                 layout.prop(uvedit, "sticky_select_mode", icon_only=True)
471
472             row = layout.row(align=True)
473             row.prop(toolsettings, "proportional_edit", icon_only=True)
474             if toolsettings.proportional_edit != 'DISABLED':
475                 row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
476
477             row = layout.row(align=True)
478             row.prop(toolsettings, "use_snap", text="")
479             row.prop(toolsettings, "snap_uv_element", icon_only=True)
480             if toolsettings.snap_uv_element != 'INCREMENT':
481                 row.prop(toolsettings, "snap_target", text="")
482
483             mesh = context.edit_object.data
484             layout.prop_search(mesh.uv_textures, "active", mesh, "uv_textures", text="")
485
486         if ima:
487             if ima.is_stereo_3d:
488                 row = layout.row()
489                 row.prop(sima, "show_stereo_3d", text="")
490
491             # layers
492             layout.template_image_layers(ima, iuser)
493
494             # draw options
495             row = layout.row(align=True)
496             row.prop(sima, "draw_channels", text="", expand=True)
497
498             row = layout.row(align=True)
499             if ima.type == 'COMPOSITE':
500                 row.operator("image.record_composite", icon='REC')
501             if ima.type == 'COMPOSITE' and ima.source in {'MOVIE', 'SEQUENCE'}:
502                 row.operator("image.play_composite", icon='PLAY')
503
504         if show_uvedit or show_maskedit or mode == 'PAINT':
505             layout.prop(sima, "use_realtime_update", icon_only=True, icon='LOCKED')
506
507
508 class MASK_MT_editor_menus(Menu):
509     bl_idname = "MASK_MT_editor_menus"
510     bl_label = ""
511
512     def draw(self, context):
513         self.draw_menus(self.layout, context)
514
515     @staticmethod
516     def draw_menus(layout, context):
517         sima = context.space_data
518         ima = sima.image
519
520         show_uvedit = sima.show_uvedit
521         show_maskedit = sima.show_maskedit
522         show_paint = sima.show_paint
523
524         layout.menu("IMAGE_MT_view")
525
526         if show_uvedit:
527             layout.menu("IMAGE_MT_select")
528         if show_maskedit:
529             layout.menu("MASK_MT_select")
530         if show_paint:
531             layout.menu("IMAGE_MT_brush")
532
533         if ima and ima.is_dirty:
534             layout.menu("IMAGE_MT_image", text="Image*")
535         else:
536             layout.menu("IMAGE_MT_image", text="Image")
537
538         if show_uvedit:
539             layout.menu("IMAGE_MT_uvs")
540         if show_maskedit:
541             layout.menu("MASK_MT_mask")
542
543
544 # -----------------------------------------------------------------------------
545 # Mask (similar code in space_clip.py, keep in sync)
546 # note! - panel placement does _not_ fit well with image panels... need to fix
547
548 from bl_ui.properties_mask_common import (
549         MASK_PT_mask,
550         MASK_PT_layers,
551         MASK_PT_spline,
552         MASK_PT_point,
553         MASK_PT_display,
554         MASK_PT_tools,
555         )
556
557
558 class IMAGE_PT_mask(MASK_PT_mask, Panel):
559     bl_space_type = 'IMAGE_EDITOR'
560     bl_region_type = 'UI'
561
562
563 class IMAGE_PT_mask_layers(MASK_PT_layers, Panel):
564     bl_space_type = 'IMAGE_EDITOR'
565     bl_region_type = 'UI'
566
567
568 class IMAGE_PT_mask_display(MASK_PT_display, Panel):
569     bl_space_type = 'IMAGE_EDITOR'
570     bl_region_type = 'UI'
571
572
573 class IMAGE_PT_active_mask_spline(MASK_PT_spline, Panel):
574     bl_space_type = 'IMAGE_EDITOR'
575     bl_region_type = 'UI'
576
577
578 class IMAGE_PT_active_mask_point(MASK_PT_point, Panel):
579     bl_space_type = 'IMAGE_EDITOR'
580     bl_region_type = 'UI'
581
582
583 class IMAGE_PT_image_properties(Panel):
584     bl_space_type = 'IMAGE_EDITOR'
585     bl_region_type = 'UI'
586     bl_label = "Image"
587
588     @classmethod
589     def poll(cls, context):
590         sima = context.space_data
591         return (sima.image)
592
593     def draw(self, context):
594         layout = self.layout
595
596         sima = context.space_data
597         iuser = sima.image_user
598
599         layout.template_image(sima, "image", iuser, multiview=True)
600
601
602 class IMAGE_PT_game_properties(Panel):
603     bl_space_type = 'IMAGE_EDITOR'
604     bl_region_type = 'UI'
605     bl_label = "Game Properties"
606
607     @classmethod
608     def poll(cls, context):
609         sima = context.space_data
610         # display even when not in game mode because these settings effect the 3d view
611         return (sima and sima.image and not sima.show_maskedit)  # and (rd.engine == 'BLENDER_GAME')
612
613     def draw(self, context):
614         layout = self.layout
615
616         sima = context.space_data
617         ima = sima.image
618
619         split = layout.split()
620
621         col = split.column()
622         col.prop(ima, "use_animation")
623         sub = col.column(align=True)
624         sub.active = ima.use_animation
625         sub.prop(ima, "frame_start", text="Start")
626         sub.prop(ima, "frame_end", text="End")
627         sub.prop(ima, "fps", text="Speed")
628
629         col.prop(ima, "use_tiles")
630         sub = col.column(align=True)
631         sub.active = ima.use_tiles or ima.use_animation
632         sub.prop(ima, "tiles_x", text="X")
633         sub.prop(ima, "tiles_y", text="Y")
634
635         col = split.column()
636         col.label(text="Clamp:")
637         col.prop(ima, "use_clamp_x", text="X")
638         col.prop(ima, "use_clamp_y", text="Y")
639         col.separator()
640         col.prop(ima, "mapping", expand=True)
641
642
643 class IMAGE_PT_view_properties(Panel):
644     bl_space_type = 'IMAGE_EDITOR'
645     bl_region_type = 'UI'
646     bl_label = "Display"
647
648     @classmethod
649     def poll(cls, context):
650         sima = context.space_data
651         return (sima and (sima.image or sima.show_uvedit))
652
653     def draw(self, context):
654         layout = self.layout
655
656         sima = context.space_data
657         ima = sima.image
658
659         show_render = sima.show_render
660         show_uvedit = sima.show_uvedit
661         show_maskedit = sima.show_maskedit
662         uvedit = sima.uv_editor
663
664         split = layout.split()
665
666         col = split.column()
667         if ima:
668             col.prop(ima, "display_aspect", text="Aspect Ratio")
669
670             col = split.column()
671             col.label(text="Coordinates:")
672             col.prop(sima, "show_repeat", text="Repeat")
673             if show_uvedit:
674                 col.prop(uvedit, "show_normalized_coords", text="Normalized")
675
676         elif show_uvedit:
677             col.label(text="Coordinates:")
678             col.prop(uvedit, "show_normalized_coords", text="Normalized")
679
680         if show_uvedit or show_maskedit:
681             col = layout.column()
682             col.label("Cursor Location:")
683             col.row().prop(sima, "cursor_location", text="")
684
685         if show_uvedit:
686             col.separator()
687
688             col.label(text="UVs:")
689             col.row().prop(uvedit, "edge_draw_type", expand=True)
690
691             split = layout.split()
692
693             col = split.column()
694             col.prop(uvedit, "show_faces")
695             col.prop(uvedit, "show_smooth_edges", text="Smooth")
696             col.prop(uvedit, "show_modified_edges", text="Modified")
697
698             col = split.column()
699             col.prop(uvedit, "show_stretch", text="Stretch")
700             sub = col.column()
701             sub.active = uvedit.show_stretch
702             sub.row().prop(uvedit, "draw_stretch_type", expand=True)
703
704             col = layout.column()
705             col.prop(uvedit, "show_other_objects")
706             row = col.row()
707             row.active = uvedit.show_other_objects
708             row.prop(uvedit, "other_uv_filter", text="Filter")
709
710         if show_render and ima:
711             layout.separator()
712             render_slot = ima.render_slots.active
713             layout.prop(render_slot, "name", text="Slot Name")
714
715
716 class IMAGE_PT_tools_transform_uvs(Panel, UVToolsPanel):
717     bl_label = "Transform"
718
719     @classmethod
720     def poll(cls, context):
721         sima = context.space_data
722         return sima.show_uvedit and not context.tool_settings.use_uv_sculpt
723
724     def draw(self, context):
725         layout = self.layout
726
727         col = layout.column(align=True)
728         col.operator("transform.translate")
729         col.operator("transform.rotate")
730         col.operator("transform.resize", text="Scale")
731         col.operator("transform.shear")
732
733
734 class IMAGE_PT_tools_align_uvs(Panel, UVToolsPanel):
735     bl_label = "UV Align"
736
737     @classmethod
738     def poll(cls, context):
739         sima = context.space_data
740         return sima.show_uvedit and not context.tool_settings.use_uv_sculpt
741
742     def draw(self, context):
743         layout = self.layout
744         layout.operator_context = 'EXEC_REGION_WIN'
745
746         split = layout.split()
747         col = split.column(align=True)
748         col.operator("transform.mirror", text="Mirror X").constraint_axis[0] = True
749         col.operator("transform.mirror", text="Mirror Y").constraint_axis[1] = True
750         col = split.column(align=True)
751         col.operator("transform.rotate", text="Rotate +90°").value = math.pi / 2
752         col.operator("transform.rotate", text="Rotate  - 90°").value = math.pi / -2
753
754         split = layout.split()
755         col = split.column(align=True)
756         col.operator("uv.align", text="Straighten").axis = 'ALIGN_S'
757         col.operator("uv.align", text="Straighten X").axis = 'ALIGN_T'
758         col.operator("uv.align", text="Straighten Y").axis = 'ALIGN_U'
759         col = split.column(align=True)
760         col.operator("uv.align", text="Align Auto").axis = 'ALIGN_AUTO'
761         col.operator("uv.align", text="Align X").axis = 'ALIGN_X'
762         col.operator("uv.align", text="Align Y").axis = 'ALIGN_Y'
763
764
765 class IMAGE_PT_tools_uvs(Panel, UVToolsPanel):
766     bl_label = "UV Tools"
767
768     @classmethod
769     def poll(cls, context):
770         sima = context.space_data
771         return sima.show_uvedit and not context.tool_settings.use_uv_sculpt
772
773     def draw(self, context):
774         layout = self.layout
775
776         col = layout.column(align=True)
777         row = col.row(align=True)
778         row.operator("uv.weld")
779         row.operator("uv.stitch")
780         col.operator("uv.remove_doubles")
781         col.operator("uv.average_islands_scale")
782         col.operator("uv.pack_islands")
783         col.operator("mesh.faces_mirror_uv")
784         col.operator("uv.minimize_stretch")
785
786         layout.label(text="UV Unwrap:")
787         row = layout.row(align=True)
788         row.operator("uv.pin").clear = False
789         row.operator("uv.pin", text="Unpin").clear = True
790         col = layout.column(align=True)
791         row = col.row(align=True)
792         row.operator("uv.mark_seam", text="Mark Seam").clear = False
793         row.operator("uv.mark_seam", text="Clear Seam").clear = True
794         col.operator("uv.seams_from_islands", text="Mark Seams from Islands")
795         col.operator("uv.unwrap")
796
797
798 class IMAGE_PT_paint(Panel, ImagePaintPanel):
799     bl_label = "Paint"
800     bl_category = "Tools"
801
802     def draw(self, context):
803         layout = self.layout
804
805         settings = context.tool_settings.image_paint
806         brush = settings.brush
807
808         col = layout.column()
809         col.template_ID_preview(settings, "brush", new="brush.add", rows=2, cols=6)
810
811         if brush:
812             brush_texpaint_common(self, context, layout, brush, settings)
813
814     @classmethod
815     def poll(cls, context):
816         sima = context.space_data
817         return sima.show_paint
818
819
820 class IMAGE_PT_tools_brush_overlay(BrushButtonsPanel, Panel):
821     bl_label = "Overlay"
822     bl_options = {'DEFAULT_CLOSED'}
823     bl_category = "Options"
824
825     def draw(self, context):
826         layout = self.layout
827
828         toolsettings = context.tool_settings.image_paint
829         brush = toolsettings.brush
830         tex_slot = brush.texture_slot
831         tex_slot_mask = brush.mask_texture_slot
832
833         col = layout.column()
834
835         col.label(text="Curve:")
836
837         row = col.row(align=True)
838         if brush.use_cursor_overlay:
839             row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')
840         else:
841             row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON')
842
843         sub = row.row(align=True)
844         sub.prop(brush, "cursor_overlay_alpha", text="Alpha")
845         sub.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
846
847         col.active = brush.brush_capabilities.has_overlay
848         col.label(text="Texture:")
849         row = col.row(align=True)
850         if tex_slot.map_mode != 'STENCIL':
851             if brush.use_primary_overlay:
852                 row.prop(brush, "use_primary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')
853             else:
854                 row.prop(brush, "use_primary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON')
855
856         sub = row.row(align=True)
857         sub.prop(brush, "texture_overlay_alpha", text="Alpha")
858         sub.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
859
860         col.label(text="Mask Texture:")
861
862         row = col.row(align=True)
863         if tex_slot_mask.map_mode != 'STENCIL':
864             if brush.use_secondary_overlay:
865                 row.prop(brush, "use_secondary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')
866             else:
867                 row.prop(brush, "use_secondary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON')
868
869         sub = row.row(align=True)
870         sub.prop(brush, "mask_overlay_alpha", text="Alpha")
871         sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
872
873
874 class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
875     bl_label = "Texture"
876     bl_options = {'DEFAULT_CLOSED'}
877     bl_category = "Tools"
878
879     def draw(self, context):
880         layout = self.layout
881
882         toolsettings = context.tool_settings.image_paint
883         brush = toolsettings.brush
884
885         col = layout.column()
886         col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
887
888         brush_texture_settings(col, brush, 0)
889
890
891 class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
892     bl_label = "Texture Mask"
893     bl_options = {'DEFAULT_CLOSED'}
894     bl_category = "Tools"
895
896     def draw(self, context):
897         layout = self.layout
898
899         brush = context.tool_settings.image_paint.brush
900
901         col = layout.column()
902
903         col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
904
905         brush_mask_texture_settings(col, brush)
906
907
908 class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, Panel):
909     bl_label = "Tool"
910     bl_options = {'DEFAULT_CLOSED'}
911     bl_category = "Options"
912
913     def draw(self, context):
914         layout = self.layout
915         toolsettings = context.tool_settings.image_paint
916         brush = toolsettings.brush
917
918         layout.prop(brush, "image_tool", text="")
919
920         row = layout.row(align=True)
921         row.prop(brush, "use_paint_sculpt", text="", icon='SCULPTMODE_HLT')
922         row.prop(brush, "use_paint_vertex", text="", icon='VPAINT_HLT')
923         row.prop(brush, "use_paint_weight", text="", icon='WPAINT_HLT')
924         row.prop(brush, "use_paint_image", text="", icon='TPAINT_HLT')
925
926
927 class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel):
928     bl_label = "Paint Stroke"
929     bl_options = {'DEFAULT_CLOSED'}
930     bl_category = "Tools"
931
932     def draw(self, context):
933         layout = self.layout
934
935         toolsettings = context.tool_settings.image_paint
936         brush = toolsettings.brush
937
938         col = layout.column()
939
940         col.label(text="Stroke Method:")
941
942         col.prop(brush, "stroke_method", text="")
943
944         if brush.use_anchor:
945             col.separator()
946             col.prop(brush, "use_edge_to_edge", "Edge To Edge")
947
948         if brush.use_airbrush:
949             col.separator()
950             col.prop(brush, "rate", text="Rate", slider=True)
951
952         if brush.use_space:
953             col.separator()
954             row = col.row(align=True)
955             row.prop(brush, "spacing", text="Spacing")
956             row.prop(brush, "use_pressure_spacing", toggle=True, text="")
957
958         if brush.use_line or brush.use_curve:
959             col.separator()
960             row = col.row(align=True)
961             row.prop(brush, "spacing", text="Spacing")
962
963         if brush.use_curve:
964             col.separator()
965             col.template_ID(brush, "paint_curve", new="paintcurve.new")
966             col.operator("paintcurve.draw")
967
968         col = layout.column()
969         col.separator()
970
971         row = col.row(align=True)
972         row.prop(brush, "use_relative_jitter", icon_only=True)
973         if brush.use_relative_jitter:
974             row.prop(brush, "jitter", slider=True)
975         else:
976             row.prop(brush, "jitter_absolute")
977         row.prop(brush, "use_pressure_jitter", toggle=True, text="")
978
979         col = layout.column()
980         col.separator()
981
982         if brush.brush_capabilities.has_smooth_stroke:
983             col.prop(brush, "use_smooth_stroke")
984
985             sub = col.column()
986             sub.active = brush.use_smooth_stroke
987             sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
988             sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
989
990             col.separator()
991
992         col.prop(toolsettings, "input_samples")
993
994
995 class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
996     bl_label = "Paint Curve"
997     bl_options = {'DEFAULT_CLOSED'}
998     bl_category = "Tools"
999
1000     def draw(self, context):
1001         layout = self.layout
1002
1003         toolsettings = context.tool_settings.image_paint
1004         brush = toolsettings.brush
1005
1006         layout.template_curve_mapping(brush, "curve")
1007
1008         col = layout.column(align=True)
1009         row = col.row(align=True)
1010         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
1011         row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
1012         row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
1013         row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
1014         row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
1015         row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
1016
1017
1018 class IMAGE_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel):
1019     bl_category = "Tools"
1020     bl_context = "imagepaint"
1021     bl_label = "Tiling"
1022     bl_options = {'DEFAULT_CLOSED'}
1023
1024     def draw(self, context):
1025         layout = self.layout
1026
1027         toolsettings = context.tool_settings
1028         ipaint = toolsettings.image_paint
1029
1030         col = layout.column(align=True)
1031         row = col.row(align=True)
1032         row.prop(ipaint, "tile_x", text="X", toggle=True)
1033         row.prop(ipaint, "tile_y", text="Y", toggle=True)
1034
1035
1036 class IMAGE_PT_tools_brush_appearance(BrushButtonsPanel, Panel):
1037     bl_label = "Appearance"
1038     bl_options = {'DEFAULT_CLOSED'}
1039     bl_category = "Options"
1040
1041     def draw(self, context):
1042         layout = self.layout
1043
1044         toolsettings = context.tool_settings.image_paint
1045         brush = toolsettings.brush
1046
1047         if brush is None:  # unlikely but can happen
1048             layout.label(text="Brush Unset")
1049             return
1050
1051         col = layout.column(align=True)
1052
1053         col.prop(toolsettings, "show_brush")
1054         sub = col.column()
1055         sub.active = toolsettings.show_brush
1056         sub.prop(brush, "cursor_color_add", text="")
1057
1058         col.separator()
1059
1060         col.prop(brush, "use_custom_icon")
1061         sub = col.column()
1062         sub.active = brush.use_custom_icon
1063         sub.prop(brush, "icon_filepath", text="")
1064
1065
1066 class IMAGE_PT_tools_paint_options(BrushButtonsPanel, Panel):
1067     bl_label = "Image Paint"
1068     bl_category = "Options"
1069
1070     def draw(self, context):
1071         layout = self.layout
1072
1073         toolsettings = context.tool_settings
1074         # brush = toolsettings.image_paint.brush
1075
1076         ups = toolsettings.unified_paint_settings
1077
1078         col = layout.column(align=True)
1079         col.label(text="Unified Settings:")
1080         row = col.row()
1081         row.prop(ups, "use_unified_size", text="Size")
1082         row.prop(ups, "use_unified_strength", text="Strength")
1083         col.prop(ups, "use_unified_color", text="Color")
1084
1085
1086 class IMAGE_UV_sculpt_curve(Panel):
1087     bl_space_type = 'IMAGE_EDITOR'
1088     bl_region_type = 'TOOLS'
1089     bl_label = "UV Sculpt Curve"
1090     bl_category = "Tools"
1091     bl_options = {'DEFAULT_CLOSED'}
1092
1093     @classmethod
1094     def poll(cls, context):
1095         sima = context.space_data
1096         toolsettings = context.tool_settings.image_paint
1097         return sima.show_uvedit and context.tool_settings.use_uv_sculpt and not (sima.show_paint and toolsettings.brush)
1098
1099     def draw(self, context):
1100         layout = self.layout
1101
1102         toolsettings = context.tool_settings
1103         uvsculpt = toolsettings.uv_sculpt
1104         brush = uvsculpt.brush
1105
1106         layout.template_curve_mapping(brush, "curve")
1107
1108         row = layout.row(align=True)
1109         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
1110         row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
1111         row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
1112         row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
1113         row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
1114         row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
1115
1116
1117 class IMAGE_UV_sculpt(Panel, ImagePaintPanel):
1118     bl_space_type = 'IMAGE_EDITOR'
1119     bl_region_type = 'TOOLS'
1120     bl_category = "Tools"
1121     bl_label = "UV Sculpt"
1122
1123     @classmethod
1124     def poll(cls, context):
1125         sima = context.space_data
1126         toolsettings = context.tool_settings.image_paint
1127         return sima.show_uvedit and context.tool_settings.use_uv_sculpt and not (sima.show_paint and toolsettings.brush)
1128
1129     def draw(self, context):
1130         layout = self.layout
1131
1132         toolsettings = context.tool_settings
1133         uvsculpt = toolsettings.uv_sculpt
1134         brush = uvsculpt.brush
1135
1136         if brush:
1137             col = layout.column()
1138
1139             row = col.row(align=True)
1140             self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
1141             self.prop_unified_size(row, context, brush, "use_pressure_size")
1142
1143             row = col.row(align=True)
1144             self.prop_unified_strength(row, context, brush, "strength", slider=True, text="Strength")
1145             self.prop_unified_strength(row, context, brush, "use_pressure_strength")
1146
1147         col = layout.column()
1148         col.prop(toolsettings, "uv_sculpt_lock_borders")
1149         col.prop(toolsettings, "uv_sculpt_all_islands")
1150
1151         col.prop(toolsettings, "uv_sculpt_tool")
1152         if toolsettings.uv_sculpt_tool == 'RELAX':
1153             col.prop(toolsettings, "uv_relax_method")
1154
1155         col.prop(uvsculpt, "show_brush")
1156
1157
1158 class IMAGE_PT_tools_mask(MASK_PT_tools, Panel):
1159     bl_space_type = 'IMAGE_EDITOR'
1160     bl_region_type = 'TOOLS'
1161     bl_category = 'Mask'
1162
1163 # --- end mask ---
1164
1165
1166 class IMAGE_PT_options_uvs(Panel, UVToolsPanel):
1167     bl_label = "UV Options"
1168     bl_category = "Options"
1169
1170     @classmethod
1171     def poll(cls, context):
1172         sima = context.space_data
1173         return sima.show_uvedit
1174
1175     def draw(self, context):
1176         layout = self.layout
1177
1178         sima = context.space_data
1179         uv = sima.uv_editor
1180         toolsettings = context.tool_settings
1181
1182         col = layout.column(align=True)
1183         col.prop(toolsettings, "use_uv_sculpt")
1184         col.prop(uv, "use_live_unwrap")
1185         col.prop(uv, "use_snap_to_pixels")
1186         col.prop(uv, "lock_bounds")
1187
1188
1189 class ImageScopesPanel:
1190     @classmethod
1191     def poll(cls, context):
1192         sima = context.space_data
1193         if not (sima and sima.image):
1194             return False
1195         # scopes are not updated in paint modes, hide
1196         if sima.mode == 'PAINT':
1197             return False
1198         ob = context.active_object
1199         if ob and ob.mode in {'TEXTURE_PAINT', 'EDIT'}:
1200             return False
1201         return True
1202
1203
1204 class IMAGE_PT_view_histogram(ImageScopesPanel, Panel):
1205     bl_space_type = 'IMAGE_EDITOR'
1206     bl_region_type = 'TOOLS'
1207     bl_label = "Histogram"
1208     bl_category = "Scopes"
1209
1210     def draw(self, context):
1211         layout = self.layout
1212
1213         sima = context.space_data
1214         hist = sima.scopes.histogram
1215
1216         layout.template_histogram(sima.scopes, "histogram")
1217         row = layout.row(align=True)
1218         row.prop(hist, "mode", expand=True)
1219         row.prop(hist, "show_line", text="")
1220
1221
1222 class IMAGE_PT_view_waveform(ImageScopesPanel, Panel):
1223     bl_space_type = 'IMAGE_EDITOR'
1224     bl_region_type = 'TOOLS'
1225     bl_label = "Waveform"
1226     bl_category = "Scopes"
1227
1228     def draw(self, context):
1229         layout = self.layout
1230
1231         sima = context.space_data
1232
1233         layout.template_waveform(sima, "scopes")
1234         row = layout.split(percentage=0.75)
1235         row.prop(sima.scopes, "waveform_alpha")
1236         row.prop(sima.scopes, "waveform_mode", text="")
1237
1238
1239 class IMAGE_PT_view_vectorscope(ImageScopesPanel, Panel):
1240     bl_space_type = 'IMAGE_EDITOR'
1241     bl_region_type = 'TOOLS'
1242     bl_label = "Vectorscope"
1243     bl_category = "Scopes"
1244
1245     def draw(self, context):
1246         layout = self.layout
1247
1248         sima = context.space_data
1249         layout.template_vectorscope(sima, "scopes")
1250         layout.prop(sima.scopes, "vectorscope_alpha")
1251
1252
1253 class IMAGE_PT_sample_line(ImageScopesPanel, Panel):
1254     bl_space_type = 'IMAGE_EDITOR'
1255     bl_region_type = 'TOOLS'
1256     bl_label = "Sample Line"
1257     bl_category = "Scopes"
1258
1259     def draw(self, context):
1260         layout = self.layout
1261
1262         sima = context.space_data
1263         hist = sima.sample_histogram
1264
1265         layout.operator("image.sample_line")
1266         layout.template_histogram(sima, "sample_histogram")
1267         row = layout.row(align=True)
1268         row.prop(hist, "mode", expand=True)
1269         row.prop(hist, "show_line", text="")
1270
1271
1272 class IMAGE_PT_scope_sample(ImageScopesPanel, Panel):
1273     bl_space_type = 'IMAGE_EDITOR'
1274     bl_region_type = 'TOOLS'
1275     bl_label = "Scope Samples"
1276     bl_category = "Scopes"
1277
1278     def draw(self, context):
1279         layout = self.layout
1280
1281         sima = context.space_data
1282
1283         row = layout.row()
1284         row.prop(sima.scopes, "use_full_resolution")
1285         sub = row.row()
1286         sub.active = not sima.scopes.use_full_resolution
1287         sub.prop(sima.scopes, "accuracy")
1288
1289
1290 # Grease Pencil properties
1291 class IMAGE_PT_grease_pencil(GreasePencilDataPanel, Panel):
1292     bl_space_type = 'IMAGE_EDITOR'
1293     bl_region_type = 'UI'
1294
1295     # NOTE: this is just a wrapper around the generic GP Panel
1296
1297
1298 # Grease Pencil palette colors
1299 class IMAGE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
1300     bl_space_type = 'IMAGE_EDITOR'
1301     bl_region_type = 'UI'
1302
1303     # NOTE: this is just a wrapper around the generic GP Panel
1304
1305
1306 # Grease Pencil drawing tools
1307 class IMAGE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
1308     bl_space_type = 'IMAGE_EDITOR'
1309
1310
1311 # Grease Pencil stroke editing tools
1312 class IMAGE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
1313     bl_space_type = 'IMAGE_EDITOR'
1314
1315
1316 # Grease Pencil stroke sculpting tools
1317 class IMAGE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
1318     bl_space_type = 'IMAGE_EDITOR'
1319
1320
1321 # Grease Pencil drawing brushes
1322 class IMAGE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
1323     bl_space_type = 'IMAGE_EDITOR'
1324
1325
1326 # Grease Pencil drawing curves
1327 class IMAGE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
1328     bl_space_type = 'IMAGE_EDITOR'
1329
1330
1331 classes = (
1332     IMAGE_MT_view,
1333     IMAGE_MT_select,
1334     IMAGE_MT_brush,
1335     IMAGE_MT_image,
1336     IMAGE_MT_image_invert,
1337     IMAGE_MT_uvs,
1338     IMAGE_MT_uvs_showhide,
1339     IMAGE_MT_uvs_proportional,
1340     IMAGE_MT_uvs_transform,
1341     IMAGE_MT_uvs_snap,
1342     IMAGE_MT_uvs_mirror,
1343     IMAGE_MT_uvs_weldalign,
1344     IMAGE_MT_uvs_select_mode,
1345     IMAGE_HT_header,
1346     MASK_MT_editor_menus,
1347     IMAGE_PT_mask,
1348     IMAGE_PT_mask_layers,
1349     IMAGE_PT_mask_display,
1350     IMAGE_PT_active_mask_spline,
1351     IMAGE_PT_active_mask_point,
1352     IMAGE_PT_image_properties,
1353     IMAGE_PT_game_properties,
1354     IMAGE_PT_view_properties,
1355     IMAGE_PT_tools_transform_uvs,
1356     IMAGE_PT_tools_align_uvs,
1357     IMAGE_PT_tools_uvs,
1358     IMAGE_PT_options_uvs,
1359     IMAGE_PT_paint,
1360     IMAGE_PT_tools_brush_overlay,
1361     IMAGE_PT_tools_brush_texture,
1362     IMAGE_PT_tools_mask,
1363     IMAGE_PT_tools_mask_texture,
1364     IMAGE_PT_tools_brush_tool,
1365     IMAGE_PT_paint_stroke,
1366     IMAGE_PT_paint_curve,
1367     IMAGE_PT_tools_imagepaint_symmetry,
1368     IMAGE_PT_tools_brush_appearance,
1369     IMAGE_PT_tools_paint_options,
1370     IMAGE_UV_sculpt,
1371     IMAGE_UV_sculpt_curve,
1372     IMAGE_PT_view_histogram,
1373     IMAGE_PT_view_waveform,
1374     IMAGE_PT_view_vectorscope,
1375     IMAGE_PT_sample_line,
1376     IMAGE_PT_scope_sample,
1377     IMAGE_PT_grease_pencil,
1378     IMAGE_PT_grease_pencil_palettecolor,
1379     IMAGE_PT_tools_grease_pencil_draw,
1380     IMAGE_PT_tools_grease_pencil_edit,
1381     IMAGE_PT_tools_grease_pencil_sculpt,
1382     IMAGE_PT_tools_grease_pencil_brush,
1383     IMAGE_PT_tools_grease_pencil_brushcurves,
1384 )
1385
1386 if __name__ == "__main__":  # only for live edit.
1387     from bpy.utils import register_class
1388     for cls in classes:
1389         register_class(cls)