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