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