GPencil: Primitive: Polyline Tool
[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
21 from bpy.types import (
22     Header,
23     Menu,
24     Panel,
25     UIList,
26 )
27 from bl_ui.properties_paint_common import (
28     UnifiedPaintPanel,
29     brush_texture_settings,
30     brush_texpaint_common,
31     brush_texpaint_common_color,
32     brush_texpaint_common_gradient,
33     brush_texpaint_common_clone,
34     brush_texpaint_common_options,
35     brush_mask_texture_settings,
36 )
37 from bl_ui.properties_grease_pencil_common import (
38     AnnotationDataPanel,
39 )
40 from bl_ui.space_toolsystem_common import (
41     ToolActivePanelHelper,
42 )
43
44 from bpy.app.translations import pgettext_iface as iface_
45
46
47 class ImagePaintPanel(UnifiedPaintPanel):
48     bl_space_type = 'IMAGE_EDITOR'
49     bl_region_type = 'UI'
50
51
52 class BrushButtonsPanel(UnifiedPaintPanel):
53     bl_space_type = 'IMAGE_EDITOR'
54     bl_region_type = 'UI'
55
56     @classmethod
57     def poll(cls, context):
58         tool_settings = context.tool_settings.image_paint
59         return tool_settings.brush
60
61
62 class IMAGE_PT_active_tool(ToolActivePanelHelper, Panel):
63     bl_space_type = 'IMAGE_EDITOR'
64     bl_region_type = 'UI'
65     bl_category = "Tool"
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         tool_settings = context.tool_settings
77         paint = tool_settings.image_paint
78
79         show_uvedit = sima.show_uvedit
80         show_render = sima.show_render
81
82         layout.prop(sima, "show_region_toolbar")
83         layout.prop(sima, "show_region_ui")
84         layout.prop(sima, "show_region_tool_header")
85         layout.prop(sima, "show_region_hud")
86
87         layout.separator()
88
89         layout.prop(sima, "use_realtime_update")
90         if show_uvedit:
91             layout.prop(tool_settings, "show_uv_local_view")
92
93         layout.prop(uv, "show_metadata")
94
95         if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'):
96             layout.prop(uv, "show_texpaint")
97             layout.prop(tool_settings, "show_uv_local_view", text="Show Same Material")
98
99         layout.separator()
100
101         layout.operator("image.view_zoom_in")
102         layout.operator("image.view_zoom_out")
103
104         layout.separator()
105
106         layout.menu("IMAGE_MT_view_zoom")
107
108         layout.separator()
109
110         if show_uvedit:
111             layout.operator("image.view_selected", text="Frame Selected")
112
113         layout.operator("image.view_all", text="Frame All")
114         layout.operator("image.view_all", text="Frame All Fit").fit_view = True
115
116         layout.operator("image.view_center_cursor", text="Center View to Cursor")
117
118         layout.separator()
119
120         if show_render:
121             layout.operator("image.render_border")
122             layout.operator("image.clear_render_border")
123
124             layout.separator()
125
126             layout.operator("image.cycle_render_slot", text="Render Slot Cycle Next")
127             layout.operator("image.cycle_render_slot", text="Render Slot Cycle Previous").reverse = True
128             layout.separator()
129
130         layout.menu("INFO_MT_area")
131
132
133 class IMAGE_MT_view_zoom(Menu):
134     bl_label = "Fractional Zoom"
135
136     def draw(self, _context):
137         layout = self.layout
138
139         ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
140
141         for i, (a, b) in enumerate(ratios):
142             if i in {3, 4}:  # Draw separators around Zoom 1:1.
143                 layout.separator()
144
145             layout.operator(
146                 "image.view_zoom_ratio",
147                 text=iface_("Zoom %d:%d") % (a, b),
148                 translate=False,
149             ).ratio = a / b
150
151
152 class IMAGE_MT_select(Menu):
153     bl_label = "Select"
154
155     def draw(self, _context):
156         layout = self.layout
157
158         layout.operator("uv.select_all", text="All").action = 'SELECT'
159         layout.operator("uv.select_all", text="None").action = 'DESELECT'
160         layout.operator("uv.select_all", text="Invert").action = 'INVERT'
161
162         layout.separator()
163
164         layout.operator("uv.select_box").pinned = False
165         layout.operator("uv.select_box", text="Box Select Pinned").pinned = True
166         layout.operator("uv.select_circle")
167
168         layout.separator()
169
170         layout.operator("uv.select_less", text="Less")
171         layout.operator("uv.select_more", text="More")
172
173         layout.separator()
174
175         layout.operator("uv.select_pinned")
176         layout.operator("uv.select_linked")
177
178         layout.separator()
179
180         layout.operator("uv.select_split")
181         layout.operator("uv.select_overlap")
182
183
184 class IMAGE_MT_brush(Menu):
185     bl_label = "Brush"
186
187     def draw(self, context):
188         layout = self.layout
189         tool_settings = context.tool_settings
190         settings = tool_settings.image_paint
191         brush = settings.brush
192
193         ups = context.tool_settings.unified_paint_settings
194         layout.prop(ups, "use_unified_size", text="Unified Size")
195         layout.prop(ups, "use_unified_strength", text="Unified Strength")
196         layout.prop(ups, "use_unified_color", text="Unified Color")
197         layout.separator()
198
199         # Brush tool.
200         layout.prop_menu_enum(brush, "image_tool")
201
202
203 class IMAGE_MT_image(Menu):
204     bl_label = "Image"
205
206     def draw(self, context):
207         layout = self.layout
208
209         sima = context.space_data
210         ima = sima.image
211         show_render = sima.show_render
212
213         layout.operator("image.new", text="New")
214         layout.operator("image.open", text="Open...", icon='FILE_FOLDER')
215
216         layout.operator("image.read_viewlayers")
217
218         if ima:
219             layout.separator()
220
221             if not show_render:
222                 layout.operator("image.replace", text="Replace...")
223                 layout.operator("image.reload", text="Reload")
224
225             layout.operator("image.external_edit", text="Edit Externally")
226
227         layout.separator()
228
229         if ima:
230             layout.operator("image.save", text="Save", icon='FILE_TICK')
231             layout.operator("image.save_as", text="Save As...")
232             layout.operator("image.save_as", text="Save a Copy...").copy = True
233
234         if ima and ima.source == 'SEQUENCE':
235             layout.operator("image.save_sequence")
236
237         layout.operator("image.save_all_modified", text="Save All Images")
238
239         if ima:
240             layout.separator()
241
242             layout.menu("IMAGE_MT_image_invert")
243             layout.operator("image.resize", text="Resize")
244
245         if ima and not show_render:
246             if ima.packed_file:
247                 if len(ima.filepath):
248                     layout.separator()
249                     layout.operator("image.unpack", text="Unpack")
250             else:
251                 layout.separator()
252                 layout.operator("image.pack", text="Pack")
253
254
255 class IMAGE_MT_image_invert(Menu):
256     bl_label = "Invert"
257
258     def draw(self, _context):
259         layout = self.layout
260
261         props = layout.operator("image.invert", text="Invert Image Colors", icon='IMAGE_RGB')
262         props.invert_r = True
263         props.invert_g = True
264         props.invert_b = True
265
266         layout.separator()
267
268         layout.operator("image.invert", text="Invert Red Channel", icon='COLOR_RED').invert_r = True
269         layout.operator("image.invert", text="Invert Green Channel", icon='COLOR_GREEN').invert_g = True
270         layout.operator("image.invert", text="Invert Blue Channel", icon='COLOR_BLUE').invert_b = True
271         layout.operator("image.invert", text="Invert Alpha Channel", icon='IMAGE_ALPHA').invert_a = True
272
273
274 class IMAGE_MT_uvs_showhide(Menu):
275     bl_label = "Show/Hide Faces"
276
277     def draw(self, _context):
278         layout = self.layout
279
280         layout.operator("uv.reveal")
281         layout.operator("uv.hide", text="Hide Selected").unselected = False
282         layout.operator("uv.hide", text="Hide Unselected").unselected = True
283
284
285 class IMAGE_MT_uvs_transform(Menu):
286     bl_label = "Transform"
287
288     def draw(self, _context):
289         layout = self.layout
290
291         layout.operator("transform.translate")
292         layout.operator("transform.rotate")
293         layout.operator("transform.resize")
294
295         layout.separator()
296
297         layout.operator("transform.shear")
298
299
300 class IMAGE_MT_uvs_snap(Menu):
301     bl_label = "Snap"
302
303     def draw(self, _context):
304         layout = self.layout
305
306         layout.operator_context = 'EXEC_REGION_WIN'
307
308         layout.operator("uv.snap_selected", text="Selected to Pixels").target = 'PIXELS'
309         layout.operator("uv.snap_selected", text="Selected to Cursor").target = 'CURSOR'
310         layout.operator("uv.snap_selected", text="Selected to Cursor (Offset)").target = 'CURSOR_OFFSET'
311         layout.operator("uv.snap_selected", text="Selected to Adjacent Unselected").target = 'ADJACENT_UNSELECTED'
312
313         layout.separator()
314
315         layout.operator("uv.snap_cursor", text="Cursor to Pixels").target = 'PIXELS'
316         layout.operator("uv.snap_cursor", text="Cursor to Selected").target = 'SELECTED'
317
318
319 class IMAGE_MT_uvs_mirror(Menu):
320     bl_label = "Mirror"
321
322     def draw(self, _context):
323         layout = self.layout
324
325         layout.operator("mesh.faces_mirror_uv")
326
327         layout.separator()
328
329         layout.operator_context = 'EXEC_REGION_WIN'
330
331         layout.operator("transform.mirror", text="X Axis").constraint_axis[0] = True
332         layout.operator("transform.mirror", text="Y Axis").constraint_axis[1] = True
333
334
335 class IMAGE_MT_uvs_weldalign(Menu):
336     bl_label = "Weld/Align"
337
338     def draw(self, _context):
339         layout = self.layout
340
341         layout.operator("uv.weld")  # W, 1.
342         layout.operator("uv.remove_doubles")
343         layout.operator_enum("uv.align", "axis")  # W, 2/3/4.
344
345
346 class IMAGE_MT_uvs(Menu):
347     bl_label = "UV"
348
349     def draw(self, context):
350         layout = self.layout
351
352         sima = context.space_data
353         uv = sima.uv_editor
354
355         layout.menu("IMAGE_MT_uvs_transform")
356         layout.menu("IMAGE_MT_uvs_mirror")
357         layout.menu("IMAGE_MT_uvs_snap")
358
359         layout.prop_menu_enum(uv, "pixel_snap_mode")
360         layout.prop(uv, "lock_bounds")
361
362         layout.separator()
363
364         layout.prop(uv, "use_live_unwrap")
365         layout.operator("uv.unwrap")
366
367         layout.separator()
368
369         layout.operator("uv.pin").clear = False
370         layout.operator("uv.pin", text="Unpin").clear = True
371
372         layout.separator()
373
374         layout.operator("uv.mark_seam").clear = False
375         layout.operator("uv.mark_seam", text="Clear Seam").clear = True
376         layout.operator("uv.seams_from_islands")
377
378         layout.separator()
379
380         layout.operator("uv.pack_islands")
381         layout.operator("uv.average_islands_scale")
382
383         layout.separator()
384
385         layout.operator("uv.minimize_stretch")
386         layout.operator("uv.stitch")
387         layout.menu("IMAGE_MT_uvs_weldalign")
388
389         layout.separator()
390
391         layout.menu("IMAGE_MT_uvs_showhide")
392
393         layout.separator()
394
395
396 class IMAGE_MT_uvs_select_mode(Menu):
397     bl_label = "UV Select Mode"
398
399     def draw(self, context):
400         layout = self.layout
401
402         layout.operator_context = 'INVOKE_REGION_WIN'
403         tool_settings = context.tool_settings
404
405         # Do smart things depending on whether uv_select_sync is on.
406
407         if tool_settings.use_uv_select_sync:
408             props = layout.operator("wm.context_set_value", text="Vertex", icon='VERTEXSEL')
409             props.value = "(True, False, False)"
410             props.data_path = "tool_settings.mesh_select_mode"
411
412             props = layout.operator("wm.context_set_value", text="Edge", icon='EDGESEL')
413             props.value = "(False, True, False)"
414             props.data_path = "tool_settings.mesh_select_mode"
415
416             props = layout.operator("wm.context_set_value", text="Face", icon='FACESEL')
417             props.value = "(False, False, True)"
418             props.data_path = "tool_settings.mesh_select_mode"
419
420         else:
421             props = layout.operator("wm.context_set_string", text="Vertex", icon='UV_VERTEXSEL')
422             props.value = 'VERTEX'
423             props.data_path = "tool_settings.uv_select_mode"
424
425             props = layout.operator("wm.context_set_string", text="Edge", icon='UV_EDGESEL')
426             props.value = 'EDGE'
427             props.data_path = "tool_settings.uv_select_mode"
428
429             props = layout.operator("wm.context_set_string", text="Face", icon='UV_FACESEL')
430             props.value = 'FACE'
431             props.data_path = "tool_settings.uv_select_mode"
432
433             props = layout.operator("wm.context_set_string", text="Island", icon='UV_ISLANDSEL')
434             props.value = 'ISLAND'
435             props.data_path = "tool_settings.uv_select_mode"
436
437
438 class IMAGE_MT_uvs_context_menu(Menu):
439     bl_label = "UV Context Menu"
440
441     def draw(self, context):
442         layout = self.layout
443
444         sima = context.space_data
445
446         # UV Edit Mode
447         if sima.show_uvedit:
448             # Add
449             layout.operator("uv.unwrap")
450             layout.operator("uv.follow_active_quads")
451
452             layout.separator()
453
454             # Modify
455             layout.operator("uv.pin").clear = False
456             layout.operator("uv.pin", text="Unpin").clear = True
457
458             layout.separator()
459
460             layout.menu("IMAGE_MT_uvs_snap")
461
462             layout.operator("transform.mirror", text="Mirror X").constraint_axis[0] = True
463             layout.operator("transform.mirror", text="Mirror Y").constraint_axis[1] = True
464
465             layout.separator()
466
467             layout.operator_enum("uv.align", "axis")  # W, 2/3/4.
468
469             layout.separator()
470
471             # Remove
472             layout.operator("uv.remove_doubles", text="Remove Double UVs")
473             layout.operator("uv.stitch")
474             layout.operator("uv.weld")
475
476
477 class IMAGE_MT_pivot_pie(Menu):
478     bl_label = "Pivot Point"
479
480     def draw(self, context):
481         layout = self.layout
482         pie = layout.menu_pie()
483
484         pie.prop_enum(context.space_data, "pivot_point", value='CENTER')
485         pie.prop_enum(context.space_data, "pivot_point", value='CURSOR')
486         pie.prop_enum(context.space_data, "pivot_point", value='INDIVIDUAL_ORIGINS')
487         pie.prop_enum(context.space_data, "pivot_point", value='MEDIAN')
488
489
490 class IMAGE_MT_uvs_snap_pie(Menu):
491     bl_label = "Snap"
492
493     def draw(self, _context):
494         layout = self.layout
495         pie = layout.menu_pie()
496
497         layout.operator_context = 'EXEC_REGION_WIN'
498
499         pie.operator(
500             "uv.snap_selected",
501             text="Selected to Pixels",
502             icon='RESTRICT_SELECT_OFF',
503         ).target = 'PIXELS'
504         pie.operator(
505             "uv.snap_cursor",
506             text="Cursor to Pixels",
507             icon='PIVOT_CURSOR',
508         ).target = 'PIXELS'
509         pie.operator(
510             "uv.snap_cursor",
511             text="Cursor to Selected",
512             icon='PIVOT_CURSOR',
513         ).target = 'SELECTED'
514         pie.operator(
515             "uv.snap_selected",
516             text="Selected to Cursor",
517             icon='RESTRICT_SELECT_OFF',
518         ).target = 'CURSOR'
519         pie.operator(
520             "uv.snap_selected",
521             text="Selected to Cursor (Offset)",
522             icon='RESTRICT_SELECT_OFF',
523         ).target = 'CURSOR_OFFSET'
524         pie.operator(
525             "uv.snap_selected",
526             text="Selected to Adjacent Unselected",
527             icon='RESTRICT_SELECT_OFF',
528         ).target = 'ADJACENT_UNSELECTED'
529
530
531 class IMAGE_HT_tool_header(Header):
532     bl_space_type = 'IMAGE_EDITOR'
533     bl_region_type = 'TOOL_HEADER'
534
535     def draw(self, context):
536         layout = self.layout
537
538         layout.template_header()
539
540         self.draw_tool_settings(context)
541
542         layout.separator_spacer()
543
544         IMAGE_HT_header.draw_xform_template(layout, context)
545
546         layout.separator_spacer()
547
548         self.draw_mode_settings(context)
549
550     def draw_tool_settings(self, context):
551         layout = self.layout
552
553         # Active Tool
554         # -----------
555         from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
556         tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout)
557         tool_mode = context.mode if tool is None else tool.mode
558
559         # Object Mode Options
560         # -------------------
561
562         # Example of how tool_settings can be accessed as pop-overs.
563
564         # TODO(campbell): editing options should be after active tool options
565         # (obviously separated for from the users POV)
566         draw_fn = getattr(_draw_tool_settings_context_mode, tool_mode, None)
567         if draw_fn is not None:
568             draw_fn(context, layout, tool)
569
570         if tool_mode == 'PAINT':
571             if (tool is not None) and tool.has_datablock:
572                 layout.popover_group(
573                     space_type='IMAGE_EDITOR',
574                     region_type='UI',
575                     context=".paint_common_2d",
576                     category="",
577                 )
578         elif tool_mode == 'UV':
579             if (tool is not None) and tool.has_datablock:
580                 layout.popover_group(space_type='IMAGE_EDITOR', region_type='UI', context=".uv_sculpt", category="")
581
582     def draw_mode_settings(self, context):
583         layout = self.layout
584
585         # Active Tool
586         # -----------
587         from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
588         tool = ToolSelectPanelHelper.tool_active_from_context(context)
589         tool_mode = context.mode if tool is None else tool.mode
590
591         if tool_mode == 'PAINT':
592             layout.popover_group(space_type='IMAGE_EDITOR', region_type='UI', context=".imagepaint_2d", category="")
593
594
595 class _draw_tool_settings_context_mode:
596     @staticmethod
597     def UV(context, layout, tool):
598         if tool and tool.has_datablock:
599             if context.mode == 'EDIT_MESH':
600                 tool_settings = context.tool_settings
601                 uv_sculpt = tool_settings.uv_sculpt
602                 brush = uv_sculpt.brush
603                 if brush:
604                     from bl_ui.properties_paint_common import UnifiedPaintPanel
605
606                     row = layout.row(align=True)
607                     UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
608                     UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
609
610                     row = layout.row(align=True)
611                     UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength", slider=True)
612                     UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
613
614     @staticmethod
615     def PAINT(context, layout, tool):
616         if (tool is None) or (not tool.has_datablock):
617             return
618
619         paint = context.tool_settings.image_paint
620         layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
621
622         brush = paint.brush
623         if brush is None:
624             return
625
626         from bl_ui.properties_paint_common import (
627             UnifiedPaintPanel,
628             brush_basic_texpaint_settings,
629         )
630         capabilities = brush.image_paint_capabilities
631         if capabilities.has_color:
632             UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
633         brush_basic_texpaint_settings(layout, context, brush, compact=True)
634
635
636 class IMAGE_HT_header(Header):
637     bl_space_type = 'IMAGE_EDITOR'
638
639     @staticmethod
640     def draw_xform_template(layout, context):
641         sima = context.space_data
642         show_uvedit = sima.show_uvedit
643         show_maskedit = sima.show_maskedit
644
645         if show_uvedit or show_maskedit:
646             layout.prop(sima, "pivot_point", icon_only=True)
647
648         if show_uvedit:
649             tool_settings = context.tool_settings
650
651             # Snap.
652             snap_uv_element = tool_settings.snap_uv_element
653             act_snap_uv_element = tool_settings.bl_rna.properties['snap_uv_element'].enum_items[snap_uv_element]
654
655             row = layout.row(align=True)
656             row.prop(tool_settings, "use_snap", text="")
657
658             sub = row.row(align=True)
659             sub.popover(
660                 panel="IMAGE_PT_snapping",
661                 icon=act_snap_uv_element.icon,
662                 text="",
663             )
664
665             # Proportional Editing
666             row = layout.row(align=True)
667             row.prop(tool_settings, "use_proportional_edit", icon_only=True)
668             sub = row.row(align=True)
669             sub.active = tool_settings.use_proportional_edit
670             sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
671
672     def draw(self, context):
673         layout = self.layout
674
675         sima = context.space_data
676         ima = sima.image
677         iuser = sima.image_user
678         tool_settings = context.tool_settings
679         show_region_tool_header = sima.show_region_tool_header
680
681         show_render = sima.show_render
682         show_uvedit = sima.show_uvedit
683         show_maskedit = sima.show_maskedit
684
685         if not show_region_tool_header:
686             layout.template_header()
687
688         if sima.mode != 'UV':
689             layout.prop(sima, "ui_mode", text="")
690
691         # UV editing.
692         if show_uvedit:
693             uvedit = sima.uv_editor
694
695             layout.prop(tool_settings, "use_uv_select_sync", text="")
696
697             if tool_settings.use_uv_select_sync:
698                 layout.template_edit_mode_selection()
699             else:
700                 layout.prop(tool_settings, "uv_select_mode", text="", expand=True)
701                 layout.prop(uvedit, "sticky_select_mode", icon_only=True)
702
703         MASK_MT_editor_menus.draw_collapsible(context, layout)
704
705         layout.separator_spacer()
706
707         if not show_region_tool_header:
708             IMAGE_HT_header.draw_xform_template(layout, context)
709
710         layout.template_ID(sima, "image", new="image.new", open="image.open")
711
712         if show_maskedit:
713             row = layout.row()
714             row.template_ID(sima, "mask", new="mask.new")
715
716         if not show_render:
717             layout.prop(sima, "use_image_pin", text="", emboss=False)
718
719         layout.separator_spacer()
720
721         if show_uvedit:
722             uvedit = sima.uv_editor
723
724             mesh = context.edit_object.data
725             layout.prop_search(mesh.uv_layers, "active", mesh, "uv_layers", text="")
726
727         if ima:
728             if ima.is_stereo_3d:
729                 row = layout.row()
730                 row.prop(sima, "show_stereo_3d", text="")
731             if show_maskedit:
732                 row = layout.row()
733                 row.popover(panel='CLIP_PT_mask_display')
734
735             # layers.
736             layout.template_image_layers(ima, iuser)
737
738             # draw options.
739             row = layout.row()
740             row.prop(sima, "display_channels", icon_only=True)
741
742             row = layout.row(align=True)
743             if ima.type == 'COMPOSITE':
744                 row.operator("image.record_composite", icon='REC')
745             if ima.type == 'COMPOSITE' and ima.source in {'MOVIE', 'SEQUENCE'}:
746                 row.operator("image.play_composite", icon='PLAY')
747
748
749 class MASK_MT_editor_menus(Menu):
750     bl_idname = "MASK_MT_editor_menus"
751     bl_label = ""
752
753     def draw(self, context):
754         layout = self.layout
755         sima = context.space_data
756         ima = sima.image
757
758         show_uvedit = sima.show_uvedit
759         show_maskedit = sima.show_maskedit
760         show_paint = sima.show_paint
761
762         layout.menu("IMAGE_MT_view")
763
764         if show_uvedit:
765             layout.menu("IMAGE_MT_select")
766         if show_maskedit:
767             layout.menu("MASK_MT_select")
768         if show_paint:
769             layout.menu("IMAGE_MT_brush")
770
771         if ima and ima.is_dirty:
772             layout.menu("IMAGE_MT_image", text="Image*")
773         else:
774             layout.menu("IMAGE_MT_image", text="Image")
775
776         if show_uvedit:
777             layout.menu("IMAGE_MT_uvs")
778         if show_maskedit:
779             layout.menu("MASK_MT_add")
780             layout.menu("MASK_MT_mask")
781
782
783 class IMAGE_MT_mask_context_menu(Menu):
784     bl_label = "Mask Context Menu"
785
786     @classmethod
787     def poll(cls, context):
788         sima = context.space_data
789         return (sima.show_maskedit)
790
791     def draw(self, context):
792         layout = self.layout
793         sima = context.space_data
794
795         if not sima.mask:
796             layout.operator("mask.new")
797             layout.separator()
798             layout.operator("mask.primitive_circle_add", icon='MESH_CIRCLE')
799             layout.operator("mask.primitive_square_add", icon='MESH_PLANE')
800         else:
801             layout.operator_menu_enum("mask.handle_type_set", "type")
802             layout.operator("mask.switch_direction")
803             layout.operator("mask.cyclic_toggle")
804
805             layout.separator()
806             layout.operator("mask.primitive_circle_add", icon='MESH_CIRCLE')
807             layout.operator("mask.primitive_square_add", icon='MESH_PLANE')
808
809             layout.separator()
810             layout.operator("mask.copy_splines", icon='COPYDOWN')
811             layout.operator("mask.paste_splines", icon='PASTEDOWN')
812
813             layout.separator()
814
815             layout.operator("mask.shape_key_rekey", text="Re-key Shape Points")
816             layout.operator("mask.feather_weight_clear")
817             layout.operator("mask.shape_key_feather_reset", text="Reset Feather Animation")
818
819             layout.separator()
820
821             layout.operator("mask.parent_set")
822             layout.operator("mask.parent_clear")
823
824             layout.separator()
825
826             layout.operator("mask.delete")
827
828 # -----------------------------------------------------------------------------
829 # Mask (similar code in space_clip.py, keep in sync)
830 # note! - panel placement does _not_ fit well with image panels... need to fix.
831
832 from bl_ui.properties_mask_common import (
833     MASK_PT_mask,
834     MASK_PT_layers,
835     MASK_PT_spline,
836     MASK_PT_point,
837     MASK_PT_display,
838 )
839
840
841 class IMAGE_PT_mask(MASK_PT_mask, Panel):
842     bl_space_type = 'IMAGE_EDITOR'
843     bl_region_type = 'UI'
844     bl_category = "Mask"
845
846
847 class IMAGE_PT_mask_layers(MASK_PT_layers, Panel):
848     bl_space_type = 'IMAGE_EDITOR'
849     bl_region_type = 'UI'
850     bl_category = "Mask"
851
852
853 class IMAGE_PT_active_mask_spline(MASK_PT_spline, Panel):
854     bl_space_type = 'IMAGE_EDITOR'
855     bl_region_type = 'UI'
856     bl_category = "Mask"
857
858
859 class IMAGE_PT_active_mask_point(MASK_PT_point, Panel):
860     bl_space_type = 'IMAGE_EDITOR'
861     bl_region_type = 'UI'
862     bl_category = "Mask"
863
864
865 # --- end mask ---
866
867 class IMAGE_PT_snapping(Panel):
868     bl_space_type = 'IMAGE_EDITOR'
869     bl_region_type = 'HEADER'
870     bl_label = "Snapping"
871
872     def draw(self, context):
873         tool_settings = context.tool_settings
874
875         layout = self.layout
876         col = layout.column()
877         col.label(text="Snapping")
878         col.prop(tool_settings, "snap_uv_element", expand=True)
879
880         if tool_settings.snap_uv_element != 'INCREMENT':
881             col.label(text="Target")
882             row = col.row(align=True)
883             row.prop(tool_settings, "snap_target", expand=True)
884
885         col.label(text="Affect")
886         row = col.row(align=True)
887         row.prop(tool_settings, "use_snap_translate", text="Move", toggle=True)
888         row.prop(tool_settings, "use_snap_rotate", text="Rotate", toggle=True)
889         row.prop(tool_settings, "use_snap_scale", text="Scale", toggle=True)
890
891
892 class IMAGE_PT_image_properties(Panel):
893     bl_space_type = 'IMAGE_EDITOR'
894     bl_region_type = 'UI'
895     bl_category = "Image"
896     bl_label = "Image"
897
898     @classmethod
899     def poll(cls, context):
900         sima = context.space_data
901         return (sima.image)
902
903     def draw(self, context):
904         layout = self.layout
905
906         sima = context.space_data
907         iuser = sima.image_user
908
909         layout.template_image(sima, "image", iuser, multiview=True)
910
911
912 class IMAGE_PT_view_display(Panel):
913     bl_space_type = 'IMAGE_EDITOR'
914     bl_region_type = 'UI'
915     bl_label = "Display"
916     bl_category = "View"
917
918     @classmethod
919     def poll(cls, context):
920         sima = context.space_data
921         return (sima and (sima.image or sima.show_uvedit))
922
923     def draw(self, context):
924         layout = self.layout
925         layout.use_property_split = True
926
927         sima = context.space_data
928         ima = sima.image
929
930         show_uvedit = sima.show_uvedit
931         uvedit = sima.uv_editor
932
933         col = layout.column()
934
935         if ima:
936             col.prop(ima, "display_aspect", text="Aspect Ratio")
937             col.prop(sima, "show_repeat", text="Repeat Image")
938
939         if show_uvedit:
940             col.prop(uvedit, "show_pixel_coords", text="Pixel Coordinates")
941
942
943 class IMAGE_PT_view_display_uv_edit_overlays(Panel):
944     bl_space_type = 'IMAGE_EDITOR'
945     bl_region_type = 'UI'
946     bl_label = "Overlays"
947     bl_parent_id = 'IMAGE_PT_view_display'
948     bl_category = "View"
949     bl_options = {'DEFAULT_CLOSED'}
950
951     @classmethod
952     def poll(cls, context):
953         sima = context.space_data
954         return (sima and (sima.show_uvedit))
955
956     def draw(self, context):
957         layout = self.layout
958         layout.use_property_split = True
959         layout.use_property_decorate = False
960
961         sima = context.space_data
962         uvedit = sima.uv_editor
963
964         col = layout.column()
965
966         col.prop(uvedit, "edge_display_type", text="Display As")
967         col.prop(uvedit, "show_faces", text="Faces")
968
969         col = layout.column()
970         col.prop(uvedit, "show_smooth_edges", text="Smooth")
971         col.prop(uvedit, "show_modified_edges", text="Modified")
972
973
974 class IMAGE_PT_view_display_uv_edit_overlays_stretch(Panel):
975     bl_space_type = 'IMAGE_EDITOR'
976     bl_region_type = 'UI'
977     bl_label = "Stretching"
978     bl_parent_id = 'IMAGE_PT_view_display_uv_edit_overlays'
979     bl_category = "View"
980     bl_options = {'DEFAULT_CLOSED'}
981
982     @classmethod
983     def poll(cls, context):
984         sima = context.space_data
985         return (sima and (sima.show_uvedit))
986
987     def draw_header(self, context):
988         sima = context.space_data
989         uvedit = sima.uv_editor
990         self.layout.prop(uvedit, "show_stretch", text="")
991
992     def draw(self, context):
993         layout = self.layout
994         layout.use_property_split = True
995
996         sima = context.space_data
997         uvedit = sima.uv_editor
998
999         layout.active = uvedit.show_stretch
1000         layout.prop(uvedit, "display_stretch_type", text="Type")
1001
1002
1003 class IMAGE_UL_render_slots(UIList):
1004     def draw_item(self, _context, layout, _data, item, _icon, _active_data, _active_propname, _index):
1005         slot = item
1006         layout.prop(slot, "name", text="", emboss=False)
1007
1008
1009 class IMAGE_PT_render_slots(Panel):
1010     bl_space_type = 'IMAGE_EDITOR'
1011     bl_region_type = 'UI'
1012     bl_category = "Image"
1013     bl_label = "Render Slots"
1014
1015     @classmethod
1016     def poll(cls, context):
1017         sima = context.space_data
1018         return (sima and sima.image and sima.show_render)
1019
1020     def draw(self, context):
1021         layout = self.layout
1022
1023         sima = context.space_data
1024         ima = sima.image
1025
1026         row = layout.row()
1027
1028         col = row.column()
1029         col.template_list(
1030             "IMAGE_UL_render_slots", "render_slots", ima,
1031             "render_slots", ima.render_slots, "active_index", rows=3,
1032         )
1033
1034         col = row.column(align=True)
1035         col.operator("image.add_render_slot", icon='ADD', text="")
1036         col.operator("image.remove_render_slot", icon='REMOVE', text="")
1037
1038         col.separator()
1039
1040         col.operator("image.clear_render_slot", icon='X', text="")
1041
1042
1043 class IMAGE_PT_paint(Panel, ImagePaintPanel):
1044     bl_label = "Brush"
1045     bl_context = ".paint_common_2d"
1046     bl_category = "Tool"
1047
1048     def draw(self, context):
1049         layout = self.layout
1050
1051         layout.use_property_split = True
1052         layout.use_property_decorate = False
1053
1054         settings = context.tool_settings.image_paint
1055         brush = settings.brush
1056
1057         col = layout.column()
1058         col.template_ID_preview(settings, "brush", new="brush.add", rows=2, cols=6)
1059
1060         if brush:
1061             brush_texpaint_common(self, context, layout, brush, settings)
1062
1063
1064 class IMAGE_PT_paint_color(Panel, ImagePaintPanel):
1065     bl_category = "Tool"
1066     bl_context = ".paint_common_2d"
1067     bl_parent_id = "IMAGE_PT_paint"
1068     bl_label = "Color Picker"
1069
1070     @classmethod
1071     def poll(cls, context):
1072         settings = context.tool_settings.image_paint
1073         brush = settings.brush
1074         capabilities = brush.image_paint_capabilities
1075
1076         return capabilities.has_color
1077
1078     def draw(self, context):
1079         layout = self.layout
1080         settings = context.tool_settings.image_paint
1081         brush = settings.brush
1082
1083         layout.prop(brush, "color_type", expand=True)
1084
1085         if brush.color_type == 'COLOR':
1086             brush_texpaint_common_color(self, context, layout, brush, settings, True)
1087         elif brush.color_type == 'GRADIENT':
1088             brush_texpaint_common_gradient(self, context, layout, brush, settings, True)
1089
1090
1091 class IMAGE_PT_paint_swatches(Panel, ImagePaintPanel):
1092     bl_category = "Tool"
1093     bl_context = ".paint_common_2d"
1094     bl_parent_id = "IMAGE_PT_paint"
1095     bl_label = "Color Palette"
1096     bl_options = {'DEFAULT_CLOSED'}
1097
1098     @classmethod
1099     def poll(cls, context):
1100         settings = context.tool_settings.image_paint
1101         brush = settings.brush
1102         capabilities = brush.image_paint_capabilities
1103
1104         return capabilities.has_color
1105
1106     def draw(self, context):
1107         layout = self.layout
1108         settings = context.tool_settings.image_paint
1109
1110         layout.template_ID(settings, "palette", new="palette.new")
1111         if settings.palette:
1112             layout.template_palette(settings, "palette", color=True)
1113
1114
1115 class IMAGE_PT_paint_clone(Panel, ImagePaintPanel):
1116     bl_category = "Tool"
1117     bl_context = ".paint_common_2d"
1118     bl_parent_id = "IMAGE_PT_paint"
1119     bl_label = "Clone from Image/UV Map"
1120     bl_options = {'DEFAULT_CLOSED'}
1121
1122     @classmethod
1123     def poll(cls, context):
1124         settings = context.tool_settings.image_paint
1125         brush = settings.brush
1126
1127         return brush.image_tool == 'CLONE'
1128
1129     def draw_header(self, context):
1130         settings = context.tool_settings.image_paint
1131         self.layout.prop(settings, "use_clone_layer", text="")
1132
1133     def draw(self, context):
1134         layout = self.layout
1135         settings = context.tool_settings.image_paint
1136         brush = settings.brush
1137
1138         layout.active = settings.use_clone_layer
1139
1140         brush_texpaint_common_clone(self, context, layout, brush, settings, True)
1141
1142
1143 class IMAGE_PT_paint_options(Panel, ImagePaintPanel):
1144     bl_category = "Tool"
1145     bl_context = ".paint_common_2d"
1146     bl_parent_id = "IMAGE_PT_paint"
1147     bl_label = "Options"
1148     bl_options = {'DEFAULT_CLOSED'}
1149
1150     @classmethod
1151     def poll(cls, context):
1152         settings = context.tool_settings.image_paint
1153         brush = settings.brush
1154         capabilities = brush.image_paint_capabilities
1155
1156         return capabilities.has_color
1157
1158     def draw(self, context):
1159         layout = self.layout
1160         settings = context.tool_settings.image_paint
1161         brush = settings.brush
1162
1163         layout.use_property_split = True
1164         layout.use_property_decorate = False  # No animation.
1165
1166         brush_texpaint_common_options(self, context, layout, brush, settings, True)
1167
1168
1169 class IMAGE_PT_tools_brush_display(BrushButtonsPanel, Panel):
1170     bl_label = "Display"
1171     bl_context = ".paint_common_2d"
1172     bl_options = {'DEFAULT_CLOSED'}
1173     bl_category = "Tool"
1174
1175     def draw(self, context):
1176         layout = self.layout
1177
1178         layout.use_property_split = True
1179         layout.use_property_decorate = False
1180
1181         tool_settings = context.tool_settings.image_paint
1182         brush = tool_settings.brush
1183         tex_slot = brush.texture_slot
1184         tex_slot_mask = brush.mask_texture_slot
1185
1186         col = layout.column()
1187
1188         row = col.row(align=True)
1189
1190         sub = row.row(align=True)
1191         sub.prop(brush, "cursor_overlay_alpha", text="Curve Alpha")
1192         sub.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
1193         row.prop(
1194             brush, "use_cursor_overlay", text="", toggle=True,
1195             icon='HIDE_OFF' if brush.use_cursor_overlay else 'HIDE_ON',
1196         )
1197
1198         col.active = brush.brush_capabilities.has_overlay
1199
1200         row = col.row(align=True)
1201
1202         sub = row.row(align=True)
1203         sub.prop(brush, "texture_overlay_alpha", text="Texture Alpha")
1204         sub.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
1205         if tex_slot.map_mode != 'STENCIL':
1206             row.prop(
1207                 brush, "use_primary_overlay", text="", toggle=True,
1208                 icon='HIDE_OFF' if brush.use_primary_overlay else 'HIDE_ON',
1209             )
1210
1211         row = col.row(align=True)
1212
1213         sub = row.row(align=True)
1214         sub.prop(brush, "mask_overlay_alpha", text="Mask Texture Alpha")
1215         sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
1216         if tex_slot_mask.map_mode != 'STENCIL':
1217             row.prop(
1218                 brush, "use_secondary_overlay", text="", toggle=True,
1219                 icon='HIDE_OFF' if brush.use_secondary_overlay else 'HIDE_ON',
1220             )
1221
1222
1223 class IMAGE_PT_tools_brush_display_show_brush(BrushButtonsPanel, Panel):
1224     bl_context = ".paint_common_2d"  # dot on purpose (access from topbar)
1225     bl_label = "Show Brush"
1226     bl_parent_id = "IMAGE_PT_tools_brush_display"
1227     bl_category = "Tool"
1228     bl_options = {'DEFAULT_CLOSED'}
1229
1230     def draw_header(self, context):
1231         settings = context.tool_settings.image_paint
1232
1233         self.layout.prop(settings, "show_brush", text="")
1234
1235     def draw(self, context):
1236         layout = self.layout
1237
1238         layout.use_property_split = True
1239         layout.use_property_decorate = False
1240
1241         settings = context.tool_settings.image_paint
1242         brush = settings.brush
1243
1244         col = layout.column()
1245         col.active = settings.show_brush
1246
1247         if context.sculpt_object and context.tool_settings.sculpt:
1248             if brush.sculpt_capabilities.has_secondary_color:
1249                 col.prop(brush, "cursor_color_add", text="Add")
1250                 col.prop(brush, "cursor_color_subtract", text="Subtract")
1251             else:
1252                 col.prop(brush, "cursor_color_add", text="Color")
1253         else:
1254             col.prop(brush, "cursor_color_add", text="Color")
1255
1256
1257 class IMAGE_PT_tools_brush_display_custom_icon(BrushButtonsPanel, Panel):
1258     bl_context = ".paint_common_2d"  # dot on purpose (access from topbar)
1259     bl_label = "Custom Icon"
1260     bl_parent_id = "IMAGE_PT_tools_brush_display"
1261     bl_category = "Tool"
1262     bl_options = {'DEFAULT_CLOSED'}
1263
1264     def draw_header(self, context):
1265         settings = context.tool_settings.image_paint
1266         brush = settings.brush
1267
1268         self.layout.prop(brush, "use_custom_icon", text="")
1269
1270     def draw(self, context):
1271         layout = self.layout
1272
1273         layout.use_property_split = True
1274         layout.use_property_decorate = False
1275
1276         settings = context.tool_settings.image_paint
1277         brush = settings.brush
1278
1279         col = layout.column()
1280         col.active = brush.use_custom_icon
1281         col.prop(brush, "icon_filepath", text="")
1282
1283
1284 class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
1285     bl_label = "Texture"
1286     bl_context = ".paint_common_2d"
1287     bl_category = "Tool"
1288     bl_options = {'DEFAULT_CLOSED'}
1289
1290     def draw(self, context):
1291         layout = self.layout
1292
1293         tool_settings = context.tool_settings.image_paint
1294         brush = tool_settings.brush
1295
1296         col = layout.column()
1297         col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
1298
1299         brush_texture_settings(col, brush, 0)
1300
1301
1302 class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
1303     bl_label = "Texture Mask"
1304     bl_context = ".paint_common_2d"
1305     bl_category = "Tool"
1306     bl_options = {'DEFAULT_CLOSED'}
1307
1308     def draw(self, context):
1309         layout = self.layout
1310
1311         brush = context.tool_settings.image_paint.brush
1312
1313         col = layout.column()
1314
1315         col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
1316
1317         brush_mask_texture_settings(col, brush)
1318
1319
1320 class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel):
1321     bl_label = "Stroke"
1322     bl_context = ".paint_common_2d"
1323     bl_category = "Tool"
1324     bl_options = {'DEFAULT_CLOSED'}
1325
1326     def draw(self, context):
1327         layout = self.layout
1328
1329         tool_settings = context.tool_settings.image_paint
1330         brush = tool_settings.brush
1331
1332         layout.use_property_split = True
1333         layout.use_property_decorate = False
1334
1335         col = layout.column()
1336
1337         col.prop(brush, "stroke_method")
1338
1339         if brush.use_anchor:
1340             col.prop(brush, "use_edge_to_edge", text="Edge To Edge")
1341
1342         if brush.use_airbrush:
1343             col.prop(brush, "rate", text="Rate", slider=True)
1344
1345         if brush.use_space:
1346             row = col.row(align=True)
1347             row.prop(brush, "spacing", text="Spacing")
1348             row.prop(brush, "use_pressure_spacing", toggle=True, text="")
1349
1350         if brush.use_line or brush.use_curve:
1351             row = col.row(align=True)
1352             row.prop(brush, "spacing", text="Spacing")
1353
1354         if brush.use_curve:
1355             col.template_ID(brush, "paint_curve", new="paintcurve.new")
1356             col.operator("paintcurve.draw")
1357
1358         row = col.row(align=True)
1359         if brush.use_relative_jitter:
1360             row.prop(brush, "jitter", slider=True)
1361         else:
1362             row.prop(brush, "jitter_absolute")
1363         row.prop(brush, "use_relative_jitter", icon_only=True)
1364         row.prop(brush, "use_pressure_jitter", toggle=True, text="")
1365
1366         col.prop(tool_settings, "input_samples")
1367
1368
1369 class IMAGE_PT_paint_stroke_smooth_stroke(BrushButtonsPanel, Panel):
1370     bl_context = ".paint_common_2d"  # dot on purpose (access from topbar)
1371     bl_label = "Smooth Stroke"
1372     bl_parent_id = "IMAGE_PT_paint_stroke"
1373     bl_category = "Tool"
1374     bl_options = {'DEFAULT_CLOSED'}
1375
1376     @classmethod
1377     def poll(cls, context):
1378         settings = context.tool_settings.image_paint
1379         brush = settings.brush
1380         if brush.brush_capabilities.has_smooth_stroke:
1381             return True
1382
1383     def draw_header(self, context):
1384         settings = context.tool_settings.image_paint
1385         brush = settings.brush
1386
1387         self.layout.prop(brush, "use_smooth_stroke", text="")
1388
1389     def draw(self, context):
1390         layout = self.layout
1391         layout.use_property_split = True
1392         layout.use_property_decorate = False
1393
1394         settings = context.tool_settings.image_paint
1395         brush = settings.brush
1396
1397         col = layout.column()
1398         col.active = brush.use_smooth_stroke
1399         col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
1400         col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
1401
1402
1403 class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
1404     bl_label = "Falloff"
1405     bl_context = ".paint_common_2d"
1406     bl_category = "Tool"
1407     bl_options = {'DEFAULT_CLOSED'}
1408
1409     def draw(self, context):
1410         layout = self.layout
1411
1412         tool_settings = context.tool_settings.image_paint
1413         brush = tool_settings.brush
1414
1415         col = layout.column(align=True)
1416         row = col.row(align=True)
1417         row.prop(brush, "curve_preset", text="")
1418
1419         if brush.curve_preset == 'CUSTOM':
1420             layout.template_curve_mapping(brush, "curve")
1421
1422             col = layout.column(align=True)
1423             row = col.row(align=True)
1424             row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
1425             row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
1426             row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
1427             row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
1428             row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
1429             row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
1430
1431
1432 class IMAGE_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel):
1433     bl_context = ".imagepaint_2d"
1434     bl_label = "Tiling"
1435     bl_category = "Tool"
1436     bl_options = {'DEFAULT_CLOSED'}
1437
1438     def draw(self, context):
1439         layout = self.layout
1440
1441         tool_settings = context.tool_settings
1442         ipaint = tool_settings.image_paint
1443
1444         col = layout.column(align=True)
1445         row = col.row(align=True)
1446         row.prop(ipaint, "tile_x", text="X", toggle=True)
1447         row.prop(ipaint, "tile_y", text="Y", toggle=True)
1448
1449
1450 class IMAGE_PT_uv_sculpt_brush(Panel):
1451     bl_space_type = 'IMAGE_EDITOR'
1452     bl_region_type = 'UI'
1453     bl_context = ".uv_sculpt"  # dot on purpose (access from topbar)
1454     bl_category = "Tool"
1455     bl_label = "Brush"
1456
1457     @classmethod
1458     def poll(cls, context):
1459         sima = context.space_data
1460         # TODO(campbell): nicer way to check if we're in uv sculpt mode.
1461         if sima and sima.show_uvedit:
1462             from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
1463             tool = ToolSelectPanelHelper.tool_active_from_context(context)
1464             if tool.has_datablock:
1465                 return True
1466         return False
1467
1468     def draw(self, context):
1469         from bl_ui.properties_paint_common import UnifiedPaintPanel
1470         layout = self.layout
1471
1472         tool_settings = context.tool_settings
1473         uvsculpt = tool_settings.uv_sculpt
1474
1475         layout.template_ID(uvsculpt, "brush")
1476
1477         brush = uvsculpt.brush
1478
1479         if not self.is_popover:
1480             if brush:
1481                 col = layout.column()
1482
1483                 row = col.row(align=True)
1484                 UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
1485                 UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
1486
1487                 row = col.row(align=True)
1488                 UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength", slider=True)
1489                 UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
1490
1491         col = layout.column()
1492         col.prop(tool_settings, "uv_sculpt_lock_borders")
1493         col.prop(tool_settings, "uv_sculpt_all_islands")
1494
1495         if brush:
1496             if brush.uv_sculpt_tool == 'RELAX':
1497                 col.prop(tool_settings, "uv_relax_method")
1498
1499         col.prop(uvsculpt, "show_brush")
1500
1501
1502 class IMAGE_PT_uv_sculpt_curve(Panel):
1503     bl_space_type = 'IMAGE_EDITOR'
1504     bl_region_type = 'UI'
1505     bl_context = ".uv_sculpt"  # dot on purpose (access from topbar)
1506     bl_category = "Tool"
1507     bl_label = "Falloff"
1508     bl_options = {'DEFAULT_CLOSED'}
1509
1510     poll = IMAGE_PT_uv_sculpt_brush.poll
1511
1512     def draw(self, context):
1513         layout = self.layout
1514
1515         tool_settings = context.tool_settings
1516         uvsculpt = tool_settings.uv_sculpt
1517         brush = uvsculpt.brush
1518
1519         if brush is not None:
1520             col = layout.column(align=True)
1521             row = col.row(align=True)
1522             row.prop(brush, "curve_preset", text="")
1523
1524             if brush.curve_preset == 'CUSTOM':
1525                 layout.template_curve_mapping(brush, "curve")
1526
1527                 row = layout.row(align=True)
1528                 row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
1529                 row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
1530                 row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
1531                 row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
1532                 row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
1533                 row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
1534
1535
1536 class ImageScopesPanel:
1537     @classmethod
1538     def poll(cls, context):
1539         sima = context.space_data
1540
1541         if not (sima and sima.image):
1542             return False
1543
1544         # scopes are not updated in paint modes, hide.
1545         if sima.mode == 'PAINT':
1546             return False
1547
1548         ob = context.active_object
1549         if ob and ob.mode in {'TEXTURE_PAINT', 'EDIT'}:
1550             return False
1551
1552         return True
1553
1554
1555 class IMAGE_PT_view_histogram(ImageScopesPanel, Panel):
1556     bl_space_type = 'IMAGE_EDITOR'
1557     bl_region_type = 'UI'
1558     bl_category = "Scopes"
1559     bl_label = "Histogram"
1560
1561     def draw(self, context):
1562         layout = self.layout
1563
1564         sima = context.space_data
1565         hist = sima.scopes.histogram
1566
1567         layout.template_histogram(sima.scopes, "histogram")
1568
1569         row = layout.row(align=True)
1570         row.prop(hist, "mode", expand=True)
1571         row.prop(hist, "show_line", text="")
1572
1573
1574 class IMAGE_PT_view_waveform(ImageScopesPanel, Panel):
1575     bl_space_type = 'IMAGE_EDITOR'
1576     bl_region_type = 'UI'
1577     bl_category = "Scopes"
1578     bl_label = "Waveform"
1579
1580     def draw(self, context):
1581         layout = self.layout
1582
1583         sima = context.space_data
1584
1585         layout.template_waveform(sima, "scopes")
1586         row = layout.split(factor=0.75)
1587         row.prop(sima.scopes, "waveform_alpha")
1588         row.prop(sima.scopes, "waveform_mode", text="")
1589
1590
1591 class IMAGE_PT_view_vectorscope(ImageScopesPanel, Panel):
1592     bl_space_type = 'IMAGE_EDITOR'
1593     bl_region_type = 'UI'
1594     bl_category = "Scopes"
1595     bl_label = "Vectorscope"
1596
1597     def draw(self, context):
1598         layout = self.layout
1599
1600         sima = context.space_data
1601         layout.template_vectorscope(sima, "scopes")
1602         layout.prop(sima.scopes, "vectorscope_alpha")
1603
1604
1605 class IMAGE_PT_sample_line(ImageScopesPanel, Panel):
1606     bl_space_type = 'IMAGE_EDITOR'
1607     bl_region_type = 'UI'
1608     bl_category = "Scopes"
1609     bl_label = "Sample Line"
1610
1611     def draw(self, context):
1612         layout = self.layout
1613
1614         sima = context.space_data
1615         hist = sima.sample_histogram
1616
1617         layout.operator("image.sample_line")
1618         layout.template_histogram(sima, "sample_histogram")
1619
1620         row = layout.row(align=True)
1621         row.prop(hist, "mode", expand=True)
1622         row.prop(hist, "show_line", text="")
1623
1624
1625 class IMAGE_PT_scope_sample(ImageScopesPanel, Panel):
1626     bl_space_type = 'IMAGE_EDITOR'
1627     bl_region_type = 'UI'
1628     bl_category = "Scopes"
1629     bl_label = "Samples"
1630     bl_options = {'DEFAULT_CLOSED'}
1631
1632     def draw(self, context):
1633         layout = self.layout
1634         layout.use_property_split = True
1635         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
1636
1637         sima = context.space_data
1638
1639         col = flow.column()
1640         col.prop(sima.scopes, "use_full_resolution")
1641
1642         col = flow.column()
1643         col.active = not sima.scopes.use_full_resolution
1644         col.prop(sima.scopes, "accuracy")
1645
1646
1647 class IMAGE_PT_uv_cursor(Panel):
1648     bl_space_type = 'IMAGE_EDITOR'
1649     bl_region_type = 'UI'
1650     bl_category = "View"
1651     bl_label = "2D Cursor"
1652
1653     @classmethod
1654     def poll(cls, context):
1655         sima = context.space_data
1656
1657         return (sima and (sima.show_uvedit or sima.show_maskedit))
1658
1659     def draw(self, context):
1660         layout = self.layout
1661
1662         sima = context.space_data
1663
1664         col = layout.column()
1665
1666         col = layout.column()
1667         col.prop(sima, "cursor_location", text="Cursor Location")
1668
1669
1670 # Grease Pencil properties
1671 class IMAGE_PT_annotation(AnnotationDataPanel, Panel):
1672     bl_space_type = 'IMAGE_EDITOR'
1673     bl_region_type = 'UI'
1674     bl_category = "View"
1675
1676     # NOTE: this is just a wrapper around the generic GP Panel.
1677
1678 # Grease Pencil drawing tools.
1679
1680
1681 classes = (
1682     IMAGE_MT_view,
1683     IMAGE_MT_view_zoom,
1684     IMAGE_MT_select,
1685     IMAGE_MT_brush,
1686     IMAGE_MT_image,
1687     IMAGE_MT_image_invert,
1688     IMAGE_MT_uvs,
1689     IMAGE_MT_uvs_showhide,
1690     IMAGE_MT_uvs_transform,
1691     IMAGE_MT_uvs_snap,
1692     IMAGE_MT_uvs_mirror,
1693     IMAGE_MT_uvs_weldalign,
1694     IMAGE_MT_uvs_select_mode,
1695     IMAGE_MT_uvs_context_menu,
1696     IMAGE_MT_mask_context_menu,
1697     IMAGE_MT_pivot_pie,
1698     IMAGE_MT_uvs_snap_pie,
1699     IMAGE_HT_tool_header,
1700     IMAGE_HT_header,
1701     MASK_MT_editor_menus,
1702     IMAGE_PT_active_tool,
1703     IMAGE_PT_mask,
1704     IMAGE_PT_mask_layers,
1705     IMAGE_PT_active_mask_spline,
1706     IMAGE_PT_active_mask_point,
1707     IMAGE_PT_snapping,
1708     IMAGE_PT_image_properties,
1709     IMAGE_UL_render_slots,
1710     IMAGE_PT_render_slots,
1711     IMAGE_PT_view_display,
1712     IMAGE_PT_view_display_uv_edit_overlays,
1713     IMAGE_PT_view_display_uv_edit_overlays_stretch,
1714     IMAGE_PT_paint,
1715     IMAGE_PT_paint_color,
1716     IMAGE_PT_paint_swatches,
1717     IMAGE_PT_paint_clone,
1718     IMAGE_PT_paint_options,
1719     IMAGE_PT_tools_brush_texture,
1720     IMAGE_PT_tools_mask_texture,
1721     IMAGE_PT_paint_stroke,
1722     IMAGE_PT_paint_stroke_smooth_stroke,
1723     IMAGE_PT_paint_curve,
1724     IMAGE_PT_tools_brush_display,
1725     IMAGE_PT_tools_brush_display_show_brush,
1726     IMAGE_PT_tools_brush_display_custom_icon,
1727     IMAGE_PT_tools_imagepaint_symmetry,
1728     IMAGE_PT_uv_sculpt_brush,
1729     IMAGE_PT_uv_sculpt_curve,
1730     IMAGE_PT_view_histogram,
1731     IMAGE_PT_view_waveform,
1732     IMAGE_PT_view_vectorscope,
1733     IMAGE_PT_sample_line,
1734     IMAGE_PT_scope_sample,
1735     IMAGE_PT_uv_cursor,
1736     IMAGE_PT_annotation,
1737 )
1738
1739
1740 if __name__ == "__main__":  # only for live edit.
1741     from bpy.utils import register_class
1742     for cls in classes:
1743         register_class(cls)