24d3ed5a0bfd1bf1805c379418d77159c05258be
[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 .properties_paint_common import (
24     UnifiedPaintPanel,
25     brush_texture_settings,
26     brush_texpaint_common,
27     brush_mask_texture_settings,
28 )
29 from .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_layers, "active", mesh, "uv_layers", 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 .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 (view_render.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         col = split.column()
621         col.prop(ima, "use_animation")
622         sub = col.column(align=True)
623         sub.active = ima.use_animation
624         sub.prop(ima, "frame_start", text="Start")
625         sub.prop(ima, "frame_end", text="End")
626         sub.prop(ima, "fps", text="Speed")
627
628         col = split.column()
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         split = layout.split()
636         col = split.column()
637         col.label(text="Clamp:")
638         col.prop(ima, "use_clamp_x", text="X")
639         col.prop(ima, "use_clamp_y", text="Y")
640
641         col = split.column()
642         col.label(text="Mapping:")
643         col.prop(ima, "mapping", expand=True)
644
645
646 class IMAGE_PT_view_properties(Panel):
647     bl_space_type = 'IMAGE_EDITOR'
648     bl_region_type = 'UI'
649     bl_label = "Display"
650
651     @classmethod
652     def poll(cls, context):
653         sima = context.space_data
654         return (sima and (sima.image or sima.show_uvedit))
655
656     def draw(self, context):
657         layout = self.layout
658
659         sima = context.space_data
660         ima = sima.image
661
662         show_render = sima.show_render
663         show_uvedit = sima.show_uvedit
664         show_maskedit = sima.show_maskedit
665         uvedit = sima.uv_editor
666
667         split = layout.split()
668
669         col = split.column()
670         if ima:
671             col.prop(ima, "display_aspect", text="Aspect Ratio")
672
673             col = split.column()
674             col.label(text="Coordinates:")
675             col.prop(sima, "show_repeat", text="Repeat")
676             if show_uvedit:
677                 col.prop(uvedit, "show_normalized_coords", text="Normalized")
678
679         elif show_uvedit:
680             col.label(text="Coordinates:")
681             col.prop(uvedit, "show_normalized_coords", text="Normalized")
682
683         if show_uvedit or show_maskedit:
684             col = layout.column()
685             col.label("Cursor Location:")
686             col.row().prop(sima, "cursor_location", text="")
687
688         if show_uvedit:
689             col.separator()
690
691             col.label(text="UVs:")
692             col.row().prop(uvedit, "edge_draw_type", expand=True)
693
694             split = layout.split()
695
696             col = split.column()
697             col.prop(uvedit, "show_faces")
698             col.prop(uvedit, "show_smooth_edges", text="Smooth")
699             col.prop(uvedit, "show_modified_edges", text="Modified")
700
701             col = split.column()
702             col.prop(uvedit, "show_stretch", text="Stretch")
703             sub = col.column()
704             sub.active = uvedit.show_stretch
705             sub.row().prop(uvedit, "draw_stretch_type", expand=True)
706
707             col = layout.column()
708             col.prop(uvedit, "show_other_objects")
709             row = col.row()
710             row.active = uvedit.show_other_objects
711             row.prop(uvedit, "other_uv_filter", text="Filter")
712
713         if show_render and ima:
714             layout.separator()
715             render_slot = ima.render_slots.active
716             layout.prop(render_slot, "name", text="Slot Name")
717
718
719 class IMAGE_PT_tools_transform_uvs(Panel, UVToolsPanel):
720     bl_label = "Transform"
721
722     @classmethod
723     def poll(cls, context):
724         sima = context.space_data
725         return sima.show_uvedit and not context.tool_settings.use_uv_sculpt
726
727     def draw(self, context):
728         layout = self.layout
729
730         col = layout.column(align=True)
731         col.operator("transform.translate")
732         col.operator("transform.rotate")
733         col.operator("transform.resize", text="Scale")
734         col.operator("transform.shear")
735
736
737 class IMAGE_PT_tools_align_uvs(Panel, UVToolsPanel):
738     bl_label = "UV Align"
739
740     @classmethod
741     def poll(cls, context):
742         sima = context.space_data
743         return sima.show_uvedit and not context.tool_settings.use_uv_sculpt
744
745     def draw(self, context):
746         layout = self.layout
747         layout.operator_context = 'EXEC_REGION_WIN'
748
749         split = layout.split()
750         col = split.column(align=True)
751         col.operator("transform.mirror", text="Mirror X").constraint_axis[0] = True
752         col.operator("transform.mirror", text="Mirror Y").constraint_axis[1] = True
753         col = split.column(align=True)
754         col.operator("transform.rotate", text="Rotate +90°").value = math.pi / 2
755         col.operator("transform.rotate", text="Rotate  - 90°").value = math.pi / -2
756
757         split = layout.split()
758         col = split.column(align=True)
759         col.operator("uv.align", text="Straighten").axis = 'ALIGN_S'
760         col.operator("uv.align", text="Straighten X").axis = 'ALIGN_T'
761         col.operator("uv.align", text="Straighten Y").axis = 'ALIGN_U'
762         col = split.column(align=True)
763         col.operator("uv.align", text="Align Auto").axis = 'ALIGN_AUTO'
764         col.operator("uv.align", text="Align X").axis = 'ALIGN_X'
765         col.operator("uv.align", text="Align Y").axis = 'ALIGN_Y'
766
767
768 class IMAGE_PT_tools_uvs(Panel, UVToolsPanel):
769     bl_label = "UV Tools"
770
771     @classmethod
772     def poll(cls, context):
773         sima = context.space_data
774         return sima.show_uvedit and not context.tool_settings.use_uv_sculpt
775
776     def draw(self, context):
777         layout = self.layout
778
779         col = layout.column(align=True)
780         row = col.row(align=True)
781         row.operator("uv.weld")
782         row.operator("uv.stitch")
783         col.operator("uv.remove_doubles")
784         col.operator("uv.average_islands_scale")
785         col.operator("uv.pack_islands")
786         col.operator("mesh.faces_mirror_uv")
787         col.operator("uv.minimize_stretch")
788
789         layout.label(text="UV Unwrap:")
790         row = layout.row(align=True)
791         row.operator("uv.pin").clear = False
792         row.operator("uv.pin", text="Unpin").clear = True
793         col = layout.column(align=True)
794         row = col.row(align=True)
795         row.operator("uv.mark_seam", text="Mark Seam").clear = False
796         row.operator("uv.mark_seam", text="Clear Seam").clear = True
797         col.operator("uv.seams_from_islands", text="Mark Seams from Islands")
798         col.operator("uv.unwrap")
799
800
801 class IMAGE_PT_paint(Panel, ImagePaintPanel):
802     bl_label = "Paint"
803     bl_category = "Tools"
804
805     def draw(self, context):
806         layout = self.layout
807
808         settings = context.tool_settings.image_paint
809         brush = settings.brush
810
811         col = layout.column()
812         col.template_ID_preview(settings, "brush", new="brush.add", rows=2, cols=6)
813
814         if brush:
815             brush_texpaint_common(self, context, layout, brush, settings)
816
817     @classmethod
818     def poll(cls, context):
819         sima = context.space_data
820         return sima.show_paint
821
822
823 class IMAGE_PT_tools_brush_overlay(BrushButtonsPanel, Panel):
824     bl_label = "Overlay"
825     bl_options = {'DEFAULT_CLOSED'}
826     bl_category = "Options"
827
828     def draw(self, context):
829         layout = self.layout
830
831         toolsettings = context.tool_settings.image_paint
832         brush = toolsettings.brush
833         tex_slot = brush.texture_slot
834         tex_slot_mask = brush.mask_texture_slot
835
836         col = layout.column()
837
838         col.label(text="Curve:")
839
840         row = col.row(align=True)
841         if brush.use_cursor_overlay:
842             row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')
843         else:
844             row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON')
845
846         sub = row.row(align=True)
847         sub.prop(brush, "cursor_overlay_alpha", text="Alpha")
848         sub.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
849
850         col.active = brush.brush_capabilities.has_overlay
851         col.label(text="Texture:")
852         row = col.row(align=True)
853         if tex_slot.map_mode != 'STENCIL':
854             if brush.use_primary_overlay:
855                 row.prop(brush, "use_primary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')
856             else:
857                 row.prop(brush, "use_primary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON')
858
859         sub = row.row(align=True)
860         sub.prop(brush, "texture_overlay_alpha", text="Alpha")
861         sub.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
862
863         col.label(text="Mask Texture:")
864
865         row = col.row(align=True)
866         if tex_slot_mask.map_mode != 'STENCIL':
867             if brush.use_secondary_overlay:
868                 row.prop(brush, "use_secondary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')
869             else:
870                 row.prop(brush, "use_secondary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON')
871
872         sub = row.row(align=True)
873         sub.prop(brush, "mask_overlay_alpha", text="Alpha")
874         sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
875
876
877 class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
878     bl_label = "Texture"
879     bl_options = {'DEFAULT_CLOSED'}
880     bl_category = "Tools"
881
882     def draw(self, context):
883         layout = self.layout
884
885         toolsettings = context.tool_settings.image_paint
886         brush = toolsettings.brush
887
888         col = layout.column()
889         col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
890
891         brush_texture_settings(col, brush, 0)
892
893
894 class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
895     bl_label = "Texture Mask"
896     bl_options = {'DEFAULT_CLOSED'}
897     bl_category = "Tools"
898
899     def draw(self, context):
900         layout = self.layout
901
902         brush = context.tool_settings.image_paint.brush
903
904         col = layout.column()
905
906         col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
907
908         brush_mask_texture_settings(col, brush)
909
910
911 class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, Panel):
912     bl_label = "Tool"
913     bl_options = {'DEFAULT_CLOSED'}
914     bl_category = "Options"
915
916     def draw(self, context):
917         layout = self.layout
918         toolsettings = context.tool_settings.image_paint
919         brush = toolsettings.brush
920
921         layout.prop(brush, "image_tool", text="")
922
923         row = layout.row(align=True)
924         row.prop(brush, "use_paint_sculpt", text="", icon='SCULPTMODE_HLT')
925         row.prop(brush, "use_paint_vertex", text="", icon='VPAINT_HLT')
926         row.prop(brush, "use_paint_weight", text="", icon='WPAINT_HLT')
927         row.prop(brush, "use_paint_image", text="", icon='TPAINT_HLT')
928
929
930 class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel):
931     bl_label = "Paint Stroke"
932     bl_options = {'DEFAULT_CLOSED'}
933     bl_category = "Tools"
934
935     def draw(self, context):
936         layout = self.layout
937
938         toolsettings = context.tool_settings.image_paint
939         brush = toolsettings.brush
940
941         col = layout.column()
942
943         col.label(text="Stroke Method:")
944
945         col.prop(brush, "stroke_method", text="")
946
947         if brush.use_anchor:
948             col.separator()
949             col.prop(brush, "use_edge_to_edge", "Edge To Edge")
950
951         if brush.use_airbrush:
952             col.separator()
953             col.prop(brush, "rate", text="Rate", slider=True)
954
955         if brush.use_space:
956             col.separator()
957             row = col.row(align=True)
958             row.prop(brush, "spacing", text="Spacing")
959             row.prop(brush, "use_pressure_spacing", toggle=True, text="")
960
961         if brush.use_line or brush.use_curve:
962             col.separator()
963             row = col.row(align=True)
964             row.prop(brush, "spacing", text="Spacing")
965
966         if brush.use_curve:
967             col.separator()
968             col.template_ID(brush, "paint_curve", new="paintcurve.new")
969             col.operator("paintcurve.draw")
970
971         col = layout.column()
972         col.separator()
973
974         row = col.row(align=True)
975         row.prop(brush, "use_relative_jitter", icon_only=True)
976         if brush.use_relative_jitter:
977             row.prop(brush, "jitter", slider=True)
978         else:
979             row.prop(brush, "jitter_absolute")
980         row.prop(brush, "use_pressure_jitter", toggle=True, text="")
981
982         col = layout.column()
983         col.separator()
984
985         if brush.brush_capabilities.has_smooth_stroke:
986             col.prop(brush, "use_smooth_stroke")
987
988             sub = col.column()
989             sub.active = brush.use_smooth_stroke
990             sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
991             sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
992
993             col.separator()
994
995         col.prop(toolsettings, "input_samples")
996
997
998 class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
999     bl_label = "Paint Curve"
1000     bl_options = {'DEFAULT_CLOSED'}
1001     bl_category = "Tools"
1002
1003     def draw(self, context):
1004         layout = self.layout
1005
1006         toolsettings = context.tool_settings.image_paint
1007         brush = toolsettings.brush
1008
1009         layout.template_curve_mapping(brush, "curve")
1010
1011         col = layout.column(align=True)
1012         row = col.row(align=True)
1013         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
1014         row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
1015         row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
1016         row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
1017         row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
1018         row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
1019
1020
1021 class IMAGE_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel):
1022     bl_category = "Tools"
1023     bl_context = "imagepaint"
1024     bl_label = "Tiling"
1025     bl_options = {'DEFAULT_CLOSED'}
1026
1027     def draw(self, context):
1028         layout = self.layout
1029
1030         toolsettings = context.tool_settings
1031         ipaint = toolsettings.image_paint
1032
1033         col = layout.column(align=True)
1034         row = col.row(align=True)
1035         row.prop(ipaint, "tile_x", text="X", toggle=True)
1036         row.prop(ipaint, "tile_y", text="Y", toggle=True)
1037
1038
1039 class IMAGE_PT_tools_brush_appearance(BrushButtonsPanel, Panel):
1040     bl_label = "Appearance"
1041     bl_options = {'DEFAULT_CLOSED'}
1042     bl_category = "Options"
1043
1044     def draw(self, context):
1045         layout = self.layout
1046
1047         toolsettings = context.tool_settings.image_paint
1048         brush = toolsettings.brush
1049
1050         if brush is None:  # unlikely but can happen
1051             layout.label(text="Brush Unset")
1052             return
1053
1054         col = layout.column(align=True)
1055
1056         col.prop(toolsettings, "show_brush")
1057         sub = col.column()
1058         sub.active = toolsettings.show_brush
1059         sub.prop(brush, "cursor_color_add", text="")
1060
1061         col.separator()
1062
1063         col.prop(brush, "use_custom_icon")
1064         sub = col.column()
1065         sub.active = brush.use_custom_icon
1066         sub.prop(brush, "icon_filepath", text="")
1067
1068
1069 class IMAGE_PT_tools_paint_options(BrushButtonsPanel, Panel):
1070     bl_label = "Image Paint"
1071     bl_category = "Options"
1072
1073     def draw(self, context):
1074         layout = self.layout
1075
1076         toolsettings = context.tool_settings
1077         # brush = toolsettings.image_paint.brush
1078
1079         ups = toolsettings.unified_paint_settings
1080
1081         col = layout.column(align=True)
1082         col.label(text="Unified Settings:")
1083         row = col.row()
1084         row.prop(ups, "use_unified_size", text="Size")
1085         row.prop(ups, "use_unified_strength", text="Strength")
1086         col.prop(ups, "use_unified_color", text="Color")
1087
1088
1089 class IMAGE_PT_uv_sculpt_curve(Panel):
1090     bl_space_type = 'IMAGE_EDITOR'
1091     bl_region_type = 'TOOLS'
1092     bl_label = "UV Sculpt Curve"
1093     bl_category = "Tools"
1094     bl_options = {'DEFAULT_CLOSED'}
1095
1096     @classmethod
1097     def poll(cls, context):
1098         sima = context.space_data
1099         toolsettings = context.tool_settings.image_paint
1100         return sima.show_uvedit and context.tool_settings.use_uv_sculpt and not (sima.show_paint and toolsettings.brush)
1101
1102     def draw(self, context):
1103         layout = self.layout
1104
1105         toolsettings = context.tool_settings
1106         uvsculpt = toolsettings.uv_sculpt
1107         brush = uvsculpt.brush
1108
1109         layout.template_curve_mapping(brush, "curve")
1110
1111         row = layout.row(align=True)
1112         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
1113         row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
1114         row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
1115         row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
1116         row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
1117         row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
1118
1119
1120 class IMAGE_PT_uv_sculpt(Panel, ImagePaintPanel):
1121     bl_space_type = 'IMAGE_EDITOR'
1122     bl_region_type = 'TOOLS'
1123     bl_category = "Tools"
1124     bl_label = "UV Sculpt"
1125
1126     @classmethod
1127     def poll(cls, context):
1128         sima = context.space_data
1129         toolsettings = context.tool_settings.image_paint
1130         return sima.show_uvedit and context.tool_settings.use_uv_sculpt and not (sima.show_paint and toolsettings.brush)
1131
1132     def draw(self, context):
1133         layout = self.layout
1134
1135         toolsettings = context.tool_settings
1136         uvsculpt = toolsettings.uv_sculpt
1137         brush = uvsculpt.brush
1138
1139         if brush:
1140             col = layout.column()
1141
1142             row = col.row(align=True)
1143             self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
1144             self.prop_unified_size(row, context, brush, "use_pressure_size")
1145
1146             row = col.row(align=True)
1147             self.prop_unified_strength(row, context, brush, "strength", slider=True, text="Strength")
1148             self.prop_unified_strength(row, context, brush, "use_pressure_strength")
1149
1150         col = layout.column()
1151         col.prop(toolsettings, "uv_sculpt_lock_borders")
1152         col.prop(toolsettings, "uv_sculpt_all_islands")
1153
1154         col.prop(toolsettings, "uv_sculpt_tool")
1155         if toolsettings.uv_sculpt_tool == 'RELAX':
1156             col.prop(toolsettings, "uv_relax_method")
1157
1158         col.prop(uvsculpt, "show_brush")
1159
1160
1161 class IMAGE_PT_tools_mask(MASK_PT_tools, Panel):
1162     bl_space_type = 'IMAGE_EDITOR'
1163     bl_region_type = 'TOOLS'
1164     bl_category = 'Mask'
1165
1166 # --- end mask ---
1167
1168
1169 class IMAGE_PT_options_uvs(Panel, UVToolsPanel):
1170     bl_label = "UV Options"
1171     bl_category = "Options"
1172
1173     @classmethod
1174     def poll(cls, context):
1175         sima = context.space_data
1176         return sima.show_uvedit
1177
1178     def draw(self, context):
1179         layout = self.layout
1180
1181         sima = context.space_data
1182         uv = sima.uv_editor
1183         toolsettings = context.tool_settings
1184
1185         col = layout.column(align=True)
1186         col.prop(toolsettings, "use_uv_sculpt")
1187         col.prop(uv, "use_live_unwrap")
1188         col.prop(uv, "use_snap_to_pixels")
1189         col.prop(uv, "lock_bounds")
1190
1191
1192 class ImageScopesPanel:
1193     @classmethod
1194     def poll(cls, context):
1195         sima = context.space_data
1196         if not (sima and sima.image):
1197             return False
1198         # scopes are not updated in paint modes, hide
1199         if sima.mode == 'PAINT':
1200             return False
1201         ob = context.active_object
1202         if ob and ob.mode in {'TEXTURE_PAINT', 'EDIT'}:
1203             return False
1204         return True
1205
1206
1207 class IMAGE_PT_view_histogram(ImageScopesPanel, Panel):
1208     bl_space_type = 'IMAGE_EDITOR'
1209     bl_region_type = 'TOOLS'
1210     bl_label = "Histogram"
1211     bl_category = "Scopes"
1212
1213     def draw(self, context):
1214         layout = self.layout
1215
1216         sima = context.space_data
1217         hist = sima.scopes.histogram
1218
1219         layout.template_histogram(sima.scopes, "histogram")
1220         row = layout.row(align=True)
1221         row.prop(hist, "mode", expand=True)
1222         row.prop(hist, "show_line", text="")
1223
1224
1225 class IMAGE_PT_view_waveform(ImageScopesPanel, Panel):
1226     bl_space_type = 'IMAGE_EDITOR'
1227     bl_region_type = 'TOOLS'
1228     bl_label = "Waveform"
1229     bl_category = "Scopes"
1230
1231     def draw(self, context):
1232         layout = self.layout
1233
1234         sima = context.space_data
1235
1236         layout.template_waveform(sima, "scopes")
1237         row = layout.split(percentage=0.75)
1238         row.prop(sima.scopes, "waveform_alpha")
1239         row.prop(sima.scopes, "waveform_mode", text="")
1240
1241
1242 class IMAGE_PT_view_vectorscope(ImageScopesPanel, Panel):
1243     bl_space_type = 'IMAGE_EDITOR'
1244     bl_region_type = 'TOOLS'
1245     bl_label = "Vectorscope"
1246     bl_category = "Scopes"
1247
1248     def draw(self, context):
1249         layout = self.layout
1250
1251         sima = context.space_data
1252         layout.template_vectorscope(sima, "scopes")
1253         layout.prop(sima.scopes, "vectorscope_alpha")
1254
1255
1256 class IMAGE_PT_sample_line(ImageScopesPanel, Panel):
1257     bl_space_type = 'IMAGE_EDITOR'
1258     bl_region_type = 'TOOLS'
1259     bl_label = "Sample Line"
1260     bl_category = "Scopes"
1261
1262     def draw(self, context):
1263         layout = self.layout
1264
1265         sima = context.space_data
1266         hist = sima.sample_histogram
1267
1268         layout.operator("image.sample_line")
1269         layout.template_histogram(sima, "sample_histogram")
1270         row = layout.row(align=True)
1271         row.prop(hist, "mode", expand=True)
1272         row.prop(hist, "show_line", text="")
1273
1274
1275 class IMAGE_PT_scope_sample(ImageScopesPanel, Panel):
1276     bl_space_type = 'IMAGE_EDITOR'
1277     bl_region_type = 'TOOLS'
1278     bl_label = "Scope Samples"
1279     bl_category = "Scopes"
1280
1281     def draw(self, context):
1282         layout = self.layout
1283
1284         sima = context.space_data
1285
1286         row = layout.row()
1287         row.prop(sima.scopes, "use_full_resolution")
1288         sub = row.row()
1289         sub.active = not sima.scopes.use_full_resolution
1290         sub.prop(sima.scopes, "accuracy")
1291
1292
1293 # Grease Pencil properties
1294 class IMAGE_PT_grease_pencil(GreasePencilDataPanel, Panel):
1295     bl_space_type = 'IMAGE_EDITOR'
1296     bl_region_type = 'UI'
1297
1298     # NOTE: this is just a wrapper around the generic GP Panel
1299
1300
1301 # Grease Pencil palette colors
1302 class IMAGE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
1303     bl_space_type = 'IMAGE_EDITOR'
1304     bl_region_type = 'UI'
1305
1306     # NOTE: this is just a wrapper around the generic GP Panel
1307
1308
1309 # Grease Pencil drawing tools
1310 class IMAGE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
1311     bl_space_type = 'IMAGE_EDITOR'
1312
1313
1314 # Grease Pencil stroke editing tools
1315 class IMAGE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
1316     bl_space_type = 'IMAGE_EDITOR'
1317
1318
1319 # Grease Pencil stroke sculpting tools
1320 class IMAGE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
1321     bl_space_type = 'IMAGE_EDITOR'
1322
1323
1324 # Grease Pencil drawing brushes
1325 class IMAGE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
1326     bl_space_type = 'IMAGE_EDITOR'
1327
1328
1329 # Grease Pencil drawing curves
1330 class IMAGE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
1331     bl_space_type = 'IMAGE_EDITOR'
1332
1333
1334 classes = (
1335     IMAGE_MT_view,
1336     IMAGE_MT_select,
1337     IMAGE_MT_brush,
1338     IMAGE_MT_image,
1339     IMAGE_MT_image_invert,
1340     IMAGE_MT_uvs,
1341     IMAGE_MT_uvs_showhide,
1342     IMAGE_MT_uvs_proportional,
1343     IMAGE_MT_uvs_transform,
1344     IMAGE_MT_uvs_snap,
1345     IMAGE_MT_uvs_mirror,
1346     IMAGE_MT_uvs_weldalign,
1347     IMAGE_MT_uvs_select_mode,
1348     IMAGE_HT_header,
1349     MASK_MT_editor_menus,
1350     IMAGE_PT_mask,
1351     IMAGE_PT_mask_layers,
1352     IMAGE_PT_mask_display,
1353     IMAGE_PT_active_mask_spline,
1354     IMAGE_PT_active_mask_point,
1355     IMAGE_PT_image_properties,
1356     IMAGE_PT_game_properties,
1357     IMAGE_PT_view_properties,
1358     IMAGE_PT_tools_transform_uvs,
1359     IMAGE_PT_tools_align_uvs,
1360     IMAGE_PT_tools_uvs,
1361     IMAGE_PT_options_uvs,
1362     IMAGE_PT_paint,
1363     IMAGE_PT_tools_brush_overlay,
1364     IMAGE_PT_tools_brush_texture,
1365     IMAGE_PT_tools_mask,
1366     IMAGE_PT_tools_mask_texture,
1367     IMAGE_PT_tools_brush_tool,
1368     IMAGE_PT_paint_stroke,
1369     IMAGE_PT_paint_curve,
1370     IMAGE_PT_tools_imagepaint_symmetry,
1371     IMAGE_PT_tools_brush_appearance,
1372     IMAGE_PT_tools_paint_options,
1373     IMAGE_PT_uv_sculpt,
1374     IMAGE_PT_uv_sculpt_curve,
1375     IMAGE_PT_view_histogram,
1376     IMAGE_PT_view_waveform,
1377     IMAGE_PT_view_vectorscope,
1378     IMAGE_PT_sample_line,
1379     IMAGE_PT_scope_sample,
1380     IMAGE_PT_grease_pencil,
1381     IMAGE_PT_grease_pencil_palettecolor,
1382     IMAGE_PT_tools_grease_pencil_draw,
1383     IMAGE_PT_tools_grease_pencil_edit,
1384     IMAGE_PT_tools_grease_pencil_sculpt,
1385     IMAGE_PT_tools_grease_pencil_brush,
1386     IMAGE_PT_tools_grease_pencil_brushcurves,
1387 )
1388
1389 if __name__ == "__main__":  # only for live edit.
1390     from bpy.utils import register_class
1391     for cls in classes:
1392         register_class(cls)