ea698f56ad461d3e45747e3f3f2de823fbf9a383
[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("uv.snap_selected", text="Selected to Pixels", icon='RESTRICT_SELECT_OFF').target = 'PIXELS'
497         pie.operator("uv.snap_cursor", text="Cursor to Pixels", icon='PIVOT_CURSOR').target = 'PIXELS'
498         pie.operator("uv.snap_cursor", text="Cursor to Selected", icon='PIVOT_CURSOR').target = 'SELECTED'
499         pie.operator("uv.snap_selected", text="Selected to Cursor", icon='RESTRICT_SELECT_OFF').target = 'CURSOR'
500         pie.operator("uv.snap_selected", text="Selected to Cursor (Offset)", icon='RESTRICT_SELECT_OFF').target = 'CURSOR_OFFSET'
501         pie.operator("uv.snap_selected", text="Selected to Adjacent Unselected", icon='RESTRICT_SELECT_OFF').target = 'ADJACENT_UNSELECTED'
502
503
504 class IMAGE_HT_tool_header(Header):
505     bl_space_type = 'IMAGE_EDITOR'
506     bl_region_type = "TOOL_HEADER"
507
508     def draw(self, context):
509         layout = self.layout
510
511         layout.template_header()
512
513         self.draw_tool_settings(context)
514
515         sima = context.space_data
516
517         layout.separator_spacer()
518
519         IMAGE_HT_header.draw_xform_template(layout, context)
520
521         layout.separator_spacer()
522
523         self.draw_mode_settings(context)
524
525     def draw_tool_settings(self, context):
526         layout = self.layout
527
528         # Active Tool
529         # -----------
530         from .space_toolsystem_common import ToolSelectPanelHelper
531         tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout)
532         tool_mode = context.mode if tool is None else tool.mode
533
534         # Object Mode Options
535         # -------------------
536
537         # Example of how tool_settings can be accessed as pop-overs.
538
539         # TODO(campbell): editing options should be after active tool options
540         # (obviously separated for from the users POV)
541         draw_fn = getattr(_draw_tool_settings_context_mode, tool_mode, None)
542         if draw_fn is not None:
543             draw_fn(context, layout, tool)
544
545         if tool_mode == 'PAINT':
546             if (tool is not None) and tool.has_datablock:
547                 layout.popover_group(space_type='IMAGE_EDITOR', region_type='UI', context=".paint_common_2d", category="")
548         elif tool_mode == 'UV':
549             if (tool is not None) and tool.has_datablock:
550                 layout.popover_group(space_type='IMAGE_EDITOR', region_type='UI', context=".uv_sculpt", category="")
551
552     def draw_mode_settings(self, context):
553         layout = self.layout
554
555         # Active Tool
556         # -----------
557         from .space_toolsystem_common import ToolSelectPanelHelper
558         tool = ToolSelectPanelHelper.tool_active_from_context(context)
559         tool_mode = context.mode if tool is None else tool.mode
560
561         if tool_mode == 'PAINT':
562             layout.popover_group(space_type='IMAGE_EDITOR', region_type='UI', context=".imagepaint_2d", category="")
563
564
565 class _draw_tool_settings_context_mode:
566     @staticmethod
567     def UV(context, layout, tool):
568         if tool and tool.has_datablock:
569             if context.mode == 'EDIT_MESH':
570                 tool_settings = context.tool_settings
571                 uv_sculpt = tool_settings.uv_sculpt
572                 brush = uv_sculpt.brush
573                 if brush:
574                     from .properties_paint_common import UnifiedPaintPanel
575
576                     row = layout.row(align=True)
577                     UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
578                     UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
579
580                     row = layout.row(align=True)
581                     UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength", slider=True)
582                     UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
583
584     @staticmethod
585     def PAINT(context, layout, tool):
586         if (tool is None) or (not tool.has_datablock):
587             return
588
589         paint = context.tool_settings.image_paint
590         layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
591
592         brush = paint.brush
593         if brush is None:
594             return
595
596         from .properties_paint_common import (
597             UnifiedPaintPanel,
598             brush_basic_texpaint_settings,
599         )
600         capabilities = brush.image_paint_capabilities
601         if capabilities.has_color:
602             UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
603         brush_basic_texpaint_settings(layout, context, brush, compact=True)
604
605
606 class IMAGE_HT_header(Header):
607     bl_space_type = 'IMAGE_EDITOR'
608
609     @staticmethod
610     def draw_xform_template(layout, context):
611         sima = context.space_data
612         show_uvedit = sima.show_uvedit
613         show_maskedit = sima.show_maskedit
614
615         if show_uvedit or show_maskedit:
616             layout.prop(sima, "pivot_point", icon_only=True)
617
618         if show_uvedit:
619             tool_settings = context.tool_settings
620
621             # Snap.
622             row = layout.row(align=True)
623             row.prop(tool_settings, "use_snap", text="")
624             row.prop(tool_settings, "snap_uv_element", icon_only=True)
625             if tool_settings.snap_uv_element != 'INCREMENT':
626                 row.prop(tool_settings, "snap_target", text="")
627
628             # Proportional Editing
629             row = layout.row(align=True)
630             row.prop(tool_settings, "use_proportional_edit", icon_only=True)
631             sub = row.row(align=True)
632             sub.active = tool_settings.use_proportional_edit
633             sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
634
635     def draw(self, context):
636         layout = self.layout
637
638         sima = context.space_data
639         ima = sima.image
640         iuser = sima.image_user
641         tool_settings = context.tool_settings
642         show_region_tool_header = sima.show_region_tool_header
643
644         show_render = sima.show_render
645         show_uvedit = sima.show_uvedit
646         show_maskedit = sima.show_maskedit
647
648         if not show_region_tool_header:
649             layout.template_header()
650
651         if sima.mode != 'UV':
652             layout.prop(sima, "ui_mode", text="")
653
654         # UV editing.
655         if show_uvedit:
656             uvedit = sima.uv_editor
657
658             layout.prop(tool_settings, "use_uv_select_sync", text="")
659
660             if tool_settings.use_uv_select_sync:
661                 layout.template_edit_mode_selection()
662             else:
663                 layout.prop(tool_settings, "uv_select_mode", text="", expand=True)
664                 layout.prop(uvedit, "sticky_select_mode", icon_only=True)
665
666         MASK_MT_editor_menus.draw_collapsible(context, layout)
667
668         layout.separator_spacer()
669
670         if not show_region_tool_header:
671             IMAGE_HT_header.draw_xform_template(layout, context)
672
673         layout.template_ID(sima, "image", new="image.new", open="image.open")
674
675         if show_maskedit:
676             row = layout.row()
677             row.template_ID(sima, "mask", new="mask.new")
678
679         if not show_render:
680             layout.prop(sima, "use_image_pin", text="")
681
682         layout.separator_spacer()
683
684         if show_uvedit:
685             uvedit = sima.uv_editor
686
687             mesh = context.edit_object.data
688             layout.prop_search(mesh.uv_layers, "active", mesh, "uv_layers", text="")
689
690         if ima:
691             if ima.is_stereo_3d:
692                 row = layout.row()
693                 row.prop(sima, "show_stereo_3d", text="")
694
695             # layers.
696             layout.template_image_layers(ima, iuser)
697
698             # draw options.
699             row = layout.row()
700             row.prop(sima, "display_channels", icon_only=True)
701
702             row = layout.row(align=True)
703             if ima.type == 'COMPOSITE':
704                 row.operator("image.record_composite", icon='REC')
705             if ima.type == 'COMPOSITE' and ima.source in {'MOVIE', 'SEQUENCE'}:
706                 row.operator("image.play_composite", icon='PLAY')
707
708
709 class MASK_MT_editor_menus(Menu):
710     bl_idname = "MASK_MT_editor_menus"
711     bl_label = ""
712
713     def draw(self, context):
714         layout = self.layout
715         sima = context.space_data
716         ima = sima.image
717
718         show_uvedit = sima.show_uvedit
719         show_maskedit = sima.show_maskedit
720         show_paint = sima.show_paint
721
722         layout.menu("IMAGE_MT_view")
723
724         if show_uvedit:
725             layout.menu("IMAGE_MT_select")
726         if show_maskedit:
727             layout.menu("MASK_MT_select")
728         if show_paint:
729             layout.menu("IMAGE_MT_brush")
730
731         if ima and ima.is_dirty:
732             layout.menu("IMAGE_MT_image", text="Image*")
733         else:
734             layout.menu("IMAGE_MT_image", text="Image")
735
736         if show_uvedit:
737             layout.menu("IMAGE_MT_uvs")
738         if show_maskedit:
739             layout.menu("MASK_MT_add")
740             layout.menu("MASK_MT_mask")
741
742
743 # -----------------------------------------------------------------------------
744 # Mask (similar code in space_clip.py, keep in sync)
745 # note! - panel placement does _not_ fit well with image panels... need to fix.
746
747 from .properties_mask_common import (
748     MASK_PT_mask,
749     MASK_PT_layers,
750     MASK_PT_spline,
751     MASK_PT_point,
752     MASK_PT_display,
753 )
754
755
756 class IMAGE_PT_mask(MASK_PT_mask, Panel):
757     bl_space_type = 'IMAGE_EDITOR'
758     bl_region_type = 'UI'
759     bl_category = "Image"
760
761
762 class IMAGE_PT_mask_layers(MASK_PT_layers, Panel):
763     bl_space_type = 'IMAGE_EDITOR'
764     bl_region_type = 'UI'
765     bl_category = "Image"
766
767
768 class IMAGE_PT_mask_display(MASK_PT_display, Panel):
769     bl_space_type = 'IMAGE_EDITOR'
770     bl_region_type = 'UI'
771     bl_category = "Image"
772
773
774 class IMAGE_PT_active_mask_spline(MASK_PT_spline, Panel):
775     bl_space_type = 'IMAGE_EDITOR'
776     bl_region_type = 'UI'
777     bl_category = "Image"
778
779
780 class IMAGE_PT_active_mask_point(MASK_PT_point, Panel):
781     bl_space_type = 'IMAGE_EDITOR'
782     bl_region_type = 'UI'
783     bl_category = "Image"
784
785
786 # --- end mask ---
787
788
789 class IMAGE_PT_image_properties(Panel):
790     bl_space_type = 'IMAGE_EDITOR'
791     bl_region_type = 'UI'
792     bl_category = "Image"
793     bl_label = "Image"
794
795     @classmethod
796     def poll(cls, context):
797         sima = context.space_data
798         return (sima.image)
799
800     def draw(self, context):
801         layout = self.layout
802
803         sima = context.space_data
804         iuser = sima.image_user
805
806         layout.template_image(sima, "image", iuser, multiview=True)
807
808
809 class IMAGE_PT_view_display(Panel):
810     bl_space_type = 'IMAGE_EDITOR'
811     bl_region_type = 'UI'
812     bl_label = "Display"
813     bl_category = "View"
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 = 'UI'
843     bl_label = "Overlays"
844     bl_parent_id = 'IMAGE_PT_view_display'
845     bl_category = "View"
846     bl_options = {'DEFAULT_CLOSED'}
847
848     @classmethod
849     def poll(cls, context):
850         sima = context.space_data
851         return (sima and (sima.show_uvedit))
852
853     def draw(self, context):
854         layout = self.layout
855         layout.use_property_split = True
856         layout.use_property_decorate = False
857
858         sima = context.space_data
859         uvedit = sima.uv_editor
860
861         col = layout.column()
862
863         col.prop(uvedit, "edge_display_type", text="Display As")
864         col.prop(uvedit, "show_edges", text="Edges")
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_stretch(Panel):
873     bl_space_type = 'IMAGE_EDITOR'
874     bl_region_type = 'UI'
875     bl_label = "Stretching"
876     bl_parent_id = 'IMAGE_PT_view_display_uv_edit_overlays'
877     bl_category = "View"
878     bl_options = {'DEFAULT_CLOSED'}
879
880     @classmethod
881     def poll(cls, context):
882         sima = context.space_data
883         return (sima and (sima.show_uvedit))
884
885     def draw_header(self, context):
886         sima = context.space_data
887         uvedit = sima.uv_editor
888         self.layout.prop(uvedit, "show_stretch", text="")
889
890     def draw(self, context):
891         layout = self.layout
892         layout.use_property_split = True
893
894         sima = context.space_data
895         uvedit = sima.uv_editor
896
897         layout.active = uvedit.show_stretch
898         layout.prop(uvedit, "display_stretch_type", text="Type")
899
900
901 class IMAGE_UL_render_slots(UIList):
902     def draw_item(self, _context, layout, _data, item, _icon, _active_data, _active_propname, _index):
903         slot = item
904         layout.prop(slot, "name", text="", emboss=False)
905
906
907 class IMAGE_PT_render_slots(Panel):
908     bl_space_type = 'IMAGE_EDITOR'
909     bl_region_type = 'UI'
910     bl_category = "Image"
911     bl_label = "Render Slots"
912
913     @classmethod
914     def poll(cls, context):
915         sima = context.space_data
916         return (sima and sima.image and sima.show_render)
917
918     def draw(self, context):
919         layout = self.layout
920
921         sima = context.space_data
922         ima = sima.image
923
924         row = layout.row()
925
926         col = row.column()
927         col.template_list(
928             "IMAGE_UL_render_slots", "render_slots", ima,
929             "render_slots", ima.render_slots, "active_index", rows=3
930         )
931
932         col = row.column(align=True)
933         col.operator("image.add_render_slot", icon='ADD', text="")
934         col.operator("image.remove_render_slot", icon='REMOVE', text="")
935
936         col.separator()
937
938         col.operator("image.clear_render_slot", icon='X', text="")
939
940
941 class IMAGE_PT_paint(Panel, ImagePaintPanel):
942     bl_label = "Brush"
943     bl_context = ".paint_common_2d"
944     bl_category = "Tool"
945
946     def draw(self, context):
947         layout = self.layout
948
949         layout.use_property_split = True
950         layout.use_property_decorate = False
951
952         settings = context.tool_settings.image_paint
953         brush = settings.brush
954
955         col = layout.column()
956         col.template_ID_preview(settings, "brush", new="brush.add", rows=2, cols=6)
957
958         if brush:
959             brush_texpaint_common(self, context, layout, brush, settings)
960
961
962 class IMAGE_PT_paint_color(Panel, ImagePaintPanel):
963     bl_category = "Tool"
964     bl_context = ".paint_common_2d"
965     bl_parent_id = "IMAGE_PT_paint"
966     bl_label = "Color Picker"
967
968     @classmethod
969     def poll(cls, context):
970         settings = context.tool_settings.image_paint
971         brush = settings.brush
972         capabilities = brush.image_paint_capabilities
973
974         return capabilities.has_color
975
976     def draw(self, context):
977         layout = self.layout
978         settings = context.tool_settings.image_paint
979         brush = settings.brush
980
981         layout.active = not brush.use_gradient
982
983         brush_texpaint_common_color(self, context, layout, brush, settings, True)
984
985
986 class IMAGE_PT_paint_swatches(Panel, ImagePaintPanel):
987     bl_category = "Tool"
988     bl_context = ".paint_common_2d"
989     bl_parent_id = "IMAGE_PT_paint"
990     bl_label = "Color Palette"
991     bl_options = {'DEFAULT_CLOSED'}
992
993     @classmethod
994     def poll(cls, context):
995         settings = context.tool_settings.image_paint
996         brush = settings.brush
997         capabilities = brush.image_paint_capabilities
998
999         return capabilities.has_color
1000
1001     def draw(self, context):
1002         layout = self.layout
1003         settings = context.tool_settings.image_paint
1004
1005         layout.template_ID(settings, "palette", new="palette.new")
1006         if settings.palette:
1007             layout.template_palette(settings, "palette", color=True)
1008
1009
1010 class IMAGE_PT_paint_gradient(Panel, ImagePaintPanel):
1011     bl_category = "Tool"
1012     bl_context = ".paint_common_2d"
1013     bl_parent_id = "IMAGE_PT_paint"
1014     bl_label = "Gradient"
1015     bl_options = {'DEFAULT_CLOSED'}
1016
1017     @classmethod
1018     def poll(cls, context):
1019         settings = context.tool_settings.image_paint
1020         brush = settings.brush
1021         capabilities = brush.image_paint_capabilities
1022
1023         return capabilities.has_color
1024
1025     def draw_header(self, context):
1026         settings = context.tool_settings.image_paint
1027         brush = settings.brush
1028         self.layout.prop(brush, "use_gradient", text="")
1029
1030     def draw(self, context):
1031         layout = self.layout
1032         layout.use_property_split = False
1033         layout.use_property_decorate = False  # No animation.
1034         settings = context.tool_settings.image_paint
1035         brush = settings.brush
1036
1037         layout.active = brush.use_gradient
1038
1039         brush_texpaint_common_gradient(self, context, layout, brush, settings, True)
1040
1041
1042 class IMAGE_PT_paint_clone(Panel, ImagePaintPanel):
1043     bl_category = "Tool"
1044     bl_context = ".paint_common_2d"
1045     bl_parent_id = "IMAGE_PT_paint"
1046     bl_label = "Clone from Image/UV Map"
1047     bl_options = {'DEFAULT_CLOSED'}
1048
1049     @classmethod
1050     def poll(cls, context):
1051         settings = context.tool_settings.image_paint
1052         brush = settings.brush
1053
1054         return brush.image_tool == 'CLONE'
1055
1056     def draw_header(self, context):
1057         settings = context.tool_settings.image_paint
1058         self.layout.prop(settings, "use_clone_layer", text="")
1059
1060     def draw(self, context):
1061         layout = self.layout
1062         settings = context.tool_settings.image_paint
1063         brush = settings.brush
1064
1065         layout.active = settings.use_clone_layer
1066
1067         brush_texpaint_common_clone(self, context, layout, brush, settings, True)
1068
1069
1070 class IMAGE_PT_paint_options(Panel, ImagePaintPanel):
1071     bl_category = "Tool"
1072     bl_context = ".paint_common_2d"
1073     bl_parent_id = "IMAGE_PT_paint"
1074     bl_label = "Options"
1075     bl_options = {'DEFAULT_CLOSED'}
1076
1077     @classmethod
1078     def poll(cls, context):
1079         settings = context.tool_settings.image_paint
1080         brush = settings.brush
1081         capabilities = brush.image_paint_capabilities
1082
1083         return capabilities.has_color
1084
1085     def draw(self, context):
1086         layout = self.layout
1087         settings = context.tool_settings.image_paint
1088         brush = settings.brush
1089
1090         layout.use_property_split = True
1091         layout.use_property_decorate = False  # No animation.
1092
1093         brush_texpaint_common_options(self, context, layout, brush, settings, True)
1094
1095
1096 class IMAGE_PT_tools_brush_display(BrushButtonsPanel, Panel):
1097     bl_label = "Display"
1098     bl_context = ".paint_common_2d"
1099     bl_options = {'DEFAULT_CLOSED'}
1100     bl_category = "Tool"
1101
1102     def draw(self, context):
1103         layout = self.layout
1104
1105         layout.use_property_split = True
1106         layout.use_property_decorate = False
1107
1108         tool_settings = context.tool_settings.image_paint
1109         brush = tool_settings.brush
1110         tex_slot = brush.texture_slot
1111         tex_slot_mask = brush.mask_texture_slot
1112
1113         col = layout.column()
1114
1115         row = col.row(align=True)
1116
1117         sub = row.row(align=True)
1118         sub.prop(brush, "cursor_overlay_alpha", text="Curve Alpha")
1119         sub.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
1120         row.prop(
1121             brush, "use_cursor_overlay", text="", toggle=True,
1122             icon='HIDE_OFF' if brush.use_cursor_overlay else 'HIDE_ON',
1123         )
1124
1125         col.active = brush.brush_capabilities.has_overlay
1126
1127         row = col.row(align=True)
1128
1129         sub = row.row(align=True)
1130         sub.prop(brush, "texture_overlay_alpha", text="Texture Alpha")
1131         sub.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
1132         if tex_slot.map_mode != 'STENCIL':
1133             row.prop(
1134                 brush, "use_primary_overlay", text="", toggle=True,
1135                 icon='HIDE_OFF' if brush.use_primary_overlay else 'HIDE_ON',
1136             )
1137
1138         row = col.row(align=True)
1139
1140         sub = row.row(align=True)
1141         sub.prop(brush, "mask_overlay_alpha", text="Mask Texture Alpha")
1142         sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
1143         if tex_slot_mask.map_mode != 'STENCIL':
1144             row.prop(
1145                 brush, "use_secondary_overlay", text="", toggle=True,
1146                 icon='HIDE_OFF' if brush.use_secondary_overlay else 'HIDE_ON',
1147             )
1148
1149
1150 class IMAGE_PT_tools_brush_display_show_brush(BrushButtonsPanel, Panel):
1151     bl_context = ".paint_common_2d"  # dot on purpose (access from topbar)
1152     bl_label = "Show Brush"
1153     bl_parent_id = "IMAGE_PT_tools_brush_display"
1154     bl_category = "Tool"
1155     bl_options = {'DEFAULT_CLOSED'}
1156
1157     def draw_header(self, context):
1158         settings = context.tool_settings.image_paint
1159
1160         self.layout.prop(settings, "show_brush", text="")
1161
1162     def draw(self, context):
1163         layout = self.layout
1164
1165         layout.use_property_split = True
1166         layout.use_property_decorate = False
1167
1168         settings = context.tool_settings.image_paint
1169         brush = settings.brush
1170
1171         col = layout.column()
1172         col.active = settings.show_brush
1173
1174         if context.sculpt_object and context.tool_settings.sculpt:
1175             if brush.sculpt_capabilities.has_secondary_color:
1176                 col.prop(brush, "cursor_color_add", text="Add")
1177                 col.prop(brush, "cursor_color_subtract", text="Subtract")
1178             else:
1179                 col.prop(brush, "cursor_color_add", text="Color")
1180         else:
1181             col.prop(brush, "cursor_color_add", text="Color")
1182
1183
1184 class IMAGE_PT_tools_brush_display_custom_icon(BrushButtonsPanel, Panel):
1185     bl_context = ".paint_common_2d"  # dot on purpose (access from topbar)
1186     bl_label = "Custom Icon"
1187     bl_parent_id = "IMAGE_PT_tools_brush_display"
1188     bl_category = "Tool"
1189     bl_options = {'DEFAULT_CLOSED'}
1190
1191     def draw_header(self, context):
1192         settings = context.tool_settings.image_paint
1193         brush = settings.brush
1194
1195         self.layout.prop(brush, "use_custom_icon", text="")
1196
1197     def draw(self, context):
1198         layout = self.layout
1199
1200         layout.use_property_split = True
1201         layout.use_property_decorate = False
1202
1203         settings = context.tool_settings.image_paint
1204         brush = settings.brush
1205
1206         col = layout.column()
1207         col.active = brush.use_custom_icon
1208         col.prop(brush, "icon_filepath", text="")
1209
1210
1211 class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
1212     bl_label = "Texture"
1213     bl_context = ".paint_common_2d"
1214     bl_category = "Tool"
1215     bl_options = {'DEFAULT_CLOSED'}
1216
1217     def draw(self, context):
1218         layout = self.layout
1219
1220         tool_settings = context.tool_settings.image_paint
1221         brush = tool_settings.brush
1222
1223         col = layout.column()
1224         col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
1225
1226         brush_texture_settings(col, brush, 0)
1227
1228
1229 class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
1230     bl_label = "Texture Mask"
1231     bl_context = ".paint_common_2d"
1232     bl_category = "Tool"
1233     bl_options = {'DEFAULT_CLOSED'}
1234
1235     def draw(self, context):
1236         layout = self.layout
1237
1238         brush = context.tool_settings.image_paint.brush
1239
1240         col = layout.column()
1241
1242         col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
1243
1244         brush_mask_texture_settings(col, brush)
1245
1246
1247 class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel):
1248     bl_label = "Stroke"
1249     bl_context = ".paint_common_2d"
1250     bl_category = "Tool"
1251     bl_options = {'DEFAULT_CLOSED'}
1252
1253     def draw(self, context):
1254         layout = self.layout
1255
1256         tool_settings = context.tool_settings.image_paint
1257         brush = tool_settings.brush
1258
1259         layout.use_property_split = True
1260         layout.use_property_decorate = False
1261
1262         col = layout.column()
1263
1264         col.prop(brush, "stroke_method")
1265
1266         if brush.use_anchor:
1267             col.prop(brush, "use_edge_to_edge", text="Edge To Edge")
1268
1269         if brush.use_airbrush:
1270             col.prop(brush, "rate", text="Rate", slider=True)
1271
1272         if brush.use_space:
1273             row = col.row(align=True)
1274             row.prop(brush, "spacing", text="Spacing")
1275             row.prop(brush, "use_pressure_spacing", toggle=True, text="")
1276
1277         if brush.use_line or brush.use_curve:
1278             row = col.row(align=True)
1279             row.prop(brush, "spacing", text="Spacing")
1280
1281         if brush.use_curve:
1282             col.template_ID(brush, "paint_curve", new="paintcurve.new")
1283             col.operator("paintcurve.draw")
1284
1285         row = col.row(align=True)
1286         if brush.use_relative_jitter:
1287             row.prop(brush, "jitter", slider=True)
1288         else:
1289             row.prop(brush, "jitter_absolute")
1290         row.prop(brush, "use_relative_jitter", icon_only=True)
1291         row.prop(brush, "use_pressure_jitter", toggle=True, text="")
1292
1293         col.prop(tool_settings, "input_samples")
1294
1295
1296 class IMAGE_PT_paint_stroke_smooth_stroke(BrushButtonsPanel, Panel):
1297     bl_context = ".paint_common_2d"  # dot on purpose (access from topbar)
1298     bl_label = "Smooth Stroke"
1299     bl_parent_id = "IMAGE_PT_paint_stroke"
1300     bl_category = "Tool"
1301     bl_options = {'DEFAULT_CLOSED'}
1302
1303     @classmethod
1304     def poll(cls, context):
1305         settings = context.tool_settings.image_paint
1306         brush = settings.brush
1307         if brush.brush_capabilities.has_smooth_stroke:
1308             return True
1309
1310     def draw_header(self, context):
1311         settings = context.tool_settings.image_paint
1312         brush = settings.brush
1313
1314         self.layout.prop(brush, "use_smooth_stroke", text="")
1315
1316     def draw(self, context):
1317         layout = self.layout
1318         layout.use_property_split = True
1319         layout.use_property_decorate = False
1320
1321         settings = context.tool_settings.image_paint
1322         brush = settings.brush
1323
1324         col = layout.column()
1325         col.active = brush.use_smooth_stroke
1326         col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
1327         col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
1328
1329
1330 class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
1331     bl_label = "Falloff"
1332     bl_context = ".paint_common_2d"
1333     bl_category = "Tool"
1334     bl_options = {'DEFAULT_CLOSED'}
1335
1336     def draw(self, context):
1337         layout = self.layout
1338
1339         tool_settings = context.tool_settings.image_paint
1340         brush = tool_settings.brush
1341
1342         layout.template_curve_mapping(brush, "curve")
1343
1344         col = layout.column(align=True)
1345         row = col.row(align=True)
1346         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
1347         row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
1348         row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
1349         row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
1350         row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
1351         row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
1352
1353
1354 class IMAGE_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel):
1355     bl_context = ".imagepaint_2d"
1356     bl_label = "Tiling"
1357     bl_category = "Tool"
1358     bl_options = {'DEFAULT_CLOSED'}
1359
1360     def draw(self, context):
1361         layout = self.layout
1362
1363         tool_settings = context.tool_settings
1364         ipaint = tool_settings.image_paint
1365
1366         col = layout.column(align=True)
1367         row = col.row(align=True)
1368         row.prop(ipaint, "tile_x", text="X", toggle=True)
1369         row.prop(ipaint, "tile_y", text="Y", toggle=True)
1370
1371
1372 class IMAGE_PT_uv_sculpt_brush(Panel):
1373     bl_space_type = 'IMAGE_EDITOR'
1374     bl_region_type = 'UI'
1375     bl_context = ".uv_sculpt"  # dot on purpose (access from topbar)
1376     bl_category = "Tool"
1377     bl_label = "Brush"
1378
1379     @classmethod
1380     def poll(cls, context):
1381         sima = context.space_data
1382         # TODO(campbell): nicer way to check if we're in uv sculpt mode.
1383         if sima and sima.show_uvedit:
1384             from .space_toolsystem_common import ToolSelectPanelHelper
1385             tool = ToolSelectPanelHelper.tool_active_from_context(context)
1386             if tool.has_datablock:
1387                 return True
1388         return False
1389
1390     def draw(self, context):
1391         from .properties_paint_common import UnifiedPaintPanel
1392         layout = self.layout
1393
1394         tool_settings = context.tool_settings
1395         uvsculpt = tool_settings.uv_sculpt
1396
1397         layout.template_ID(uvsculpt, "brush")
1398
1399         brush = uvsculpt.brush
1400
1401         if not self.is_popover:
1402             if brush:
1403                 col = layout.column()
1404
1405                 row = col.row(align=True)
1406                 UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
1407                 UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
1408
1409                 row = col.row(align=True)
1410                 UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength", slider=True)
1411                 UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
1412
1413         col = layout.column()
1414         col.prop(tool_settings, "uv_sculpt_lock_borders")
1415         col.prop(tool_settings, "uv_sculpt_all_islands")
1416
1417         if brush:
1418             if brush.uv_sculpt_tool == 'RELAX':
1419                 col.prop(tool_settings, "uv_relax_method")
1420
1421         col.prop(uvsculpt, "show_brush")
1422
1423
1424 class IMAGE_PT_uv_sculpt_curve(Panel):
1425     bl_space_type = 'IMAGE_EDITOR'
1426     bl_region_type = 'UI'
1427     bl_context = ".uv_sculpt"  # dot on purpose (access from topbar)
1428     bl_category = "Tool"
1429     bl_label = "Falloff"
1430     bl_options = {'DEFAULT_CLOSED'}
1431
1432     poll = IMAGE_PT_uv_sculpt_brush.poll
1433
1434     def draw(self, context):
1435         layout = self.layout
1436
1437         tool_settings = context.tool_settings
1438         uvsculpt = tool_settings.uv_sculpt
1439         brush = uvsculpt.brush
1440
1441         if brush is not None:
1442             layout.template_curve_mapping(brush, "curve")
1443
1444             row = layout.row(align=True)
1445             row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
1446             row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
1447             row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
1448             row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
1449             row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
1450             row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
1451
1452
1453
1454 class ImageScopesPanel:
1455     @classmethod
1456     def poll(cls, context):
1457         sima = context.space_data
1458
1459         if not (sima and sima.image):
1460             return False
1461
1462         # scopes are not updated in paint modes, hide.
1463         if sima.mode == 'PAINT':
1464             return False
1465
1466         ob = context.active_object
1467         if ob and ob.mode in {'TEXTURE_PAINT', 'EDIT'}:
1468             return False
1469
1470         return True
1471
1472
1473 class IMAGE_PT_view_histogram(ImageScopesPanel, Panel):
1474     bl_space_type = 'IMAGE_EDITOR'
1475     bl_region_type = 'UI'
1476     bl_category = "Scopes"
1477     bl_label = "Histogram"
1478
1479     def draw(self, context):
1480         layout = self.layout
1481
1482         sima = context.space_data
1483         hist = sima.scopes.histogram
1484
1485         layout.template_histogram(sima.scopes, "histogram")
1486
1487         row = layout.row(align=True)
1488         row.prop(hist, "mode", expand=True)
1489         row.prop(hist, "show_line", text="")
1490
1491
1492 class IMAGE_PT_view_waveform(ImageScopesPanel, Panel):
1493     bl_space_type = 'IMAGE_EDITOR'
1494     bl_region_type = 'UI'
1495     bl_category = "Scopes"
1496     bl_label = "Waveform"
1497
1498     def draw(self, context):
1499         layout = self.layout
1500
1501         sima = context.space_data
1502
1503         layout.template_waveform(sima, "scopes")
1504         row = layout.split(factor=0.75)
1505         row.prop(sima.scopes, "waveform_alpha")
1506         row.prop(sima.scopes, "waveform_mode", text="")
1507
1508
1509 class IMAGE_PT_view_vectorscope(ImageScopesPanel, Panel):
1510     bl_space_type = 'IMAGE_EDITOR'
1511     bl_region_type = 'UI'
1512     bl_category = "Scopes"
1513     bl_label = "Vectorscope"
1514
1515     def draw(self, context):
1516         layout = self.layout
1517
1518         sima = context.space_data
1519         layout.template_vectorscope(sima, "scopes")
1520         layout.prop(sima.scopes, "vectorscope_alpha")
1521
1522
1523 class IMAGE_PT_sample_line(ImageScopesPanel, Panel):
1524     bl_space_type = 'IMAGE_EDITOR'
1525     bl_region_type = 'UI'
1526     bl_category = "Scopes"
1527     bl_label = "Sample Line"
1528
1529     def draw(self, context):
1530         layout = self.layout
1531
1532         sima = context.space_data
1533         hist = sima.sample_histogram
1534
1535         layout.operator("image.sample_line")
1536         layout.template_histogram(sima, "sample_histogram")
1537
1538         row = layout.row(align=True)
1539         row.prop(hist, "mode", expand=True)
1540         row.prop(hist, "show_line", text="")
1541
1542
1543 class IMAGE_PT_scope_sample(ImageScopesPanel, Panel):
1544     bl_space_type = 'IMAGE_EDITOR'
1545     bl_region_type = 'UI'
1546     bl_category = "Scopes"
1547     bl_label = "Samples"
1548     bl_options = {'DEFAULT_CLOSED'}
1549
1550     def draw(self, context):
1551         layout = self.layout
1552         layout.use_property_split = True
1553         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
1554
1555         sima = context.space_data
1556
1557         col = flow.column()
1558         col.prop(sima.scopes, "use_full_resolution")
1559
1560         col = flow.column()
1561         col.active = not sima.scopes.use_full_resolution
1562         col.prop(sima.scopes, "accuracy")
1563
1564
1565 class IMAGE_PT_uv_cursor(Panel):
1566     bl_space_type = 'IMAGE_EDITOR'
1567     bl_region_type = 'UI'
1568     bl_category = "View"
1569     bl_label = "2D Cursor"
1570
1571     @classmethod
1572     def poll(cls, context):
1573         sima = context.space_data
1574
1575         return (sima and (sima.show_uvedit or sima.show_maskedit))
1576
1577     def draw(self, context):
1578         layout = self.layout
1579
1580         sima = context.space_data
1581
1582         col = layout.column()
1583
1584         col = layout.column()
1585         col.prop(sima, "cursor_location", text="Cursor Location")
1586
1587
1588 # Grease Pencil properties
1589 class IMAGE_PT_grease_pencil(AnnotationDataPanel, Panel):
1590     bl_space_type = 'IMAGE_EDITOR'
1591     bl_region_type = 'UI'
1592     bl_category = "View"
1593
1594     # NOTE: this is just a wrapper around the generic GP Panel.
1595
1596 # Grease Pencil drawing tools.
1597
1598
1599 classes = (
1600     IMAGE_MT_view,
1601     IMAGE_MT_view_zoom,
1602     IMAGE_MT_select,
1603     IMAGE_MT_brush,
1604     IMAGE_MT_image,
1605     IMAGE_MT_image_invert,
1606     IMAGE_MT_uvs,
1607     IMAGE_MT_uvs_showhide,
1608     IMAGE_MT_uvs_transform,
1609     IMAGE_MT_uvs_snap,
1610     IMAGE_MT_uvs_mirror,
1611     IMAGE_MT_uvs_weldalign,
1612     IMAGE_MT_uvs_select_mode,
1613     IMAGE_MT_uvs_context_menu,
1614     IMAGE_MT_pivot_pie,
1615     IMAGE_MT_uvs_snap_pie,
1616     IMAGE_HT_tool_header,
1617     IMAGE_HT_header,
1618     MASK_MT_editor_menus,
1619     IMAGE_PT_active_tool,
1620     IMAGE_PT_mask,
1621     IMAGE_PT_mask_layers,
1622     IMAGE_PT_mask_display,
1623     IMAGE_PT_active_mask_spline,
1624     IMAGE_PT_active_mask_point,
1625     IMAGE_PT_image_properties,
1626     IMAGE_UL_render_slots,
1627     IMAGE_PT_render_slots,
1628     IMAGE_PT_view_display,
1629     IMAGE_PT_view_display_uv_edit_overlays,
1630     IMAGE_PT_view_display_uv_edit_overlays_stretch,
1631     IMAGE_PT_paint,
1632     IMAGE_PT_paint_color,
1633     IMAGE_PT_paint_swatches,
1634     IMAGE_PT_paint_gradient,
1635     IMAGE_PT_paint_clone,
1636     IMAGE_PT_paint_options,
1637     IMAGE_PT_tools_brush_texture,
1638     IMAGE_PT_tools_mask_texture,
1639     IMAGE_PT_paint_stroke,
1640     IMAGE_PT_paint_stroke_smooth_stroke,
1641     IMAGE_PT_paint_curve,
1642     IMAGE_PT_tools_brush_display,
1643     IMAGE_PT_tools_brush_display_show_brush,
1644     IMAGE_PT_tools_brush_display_custom_icon,
1645     IMAGE_PT_tools_imagepaint_symmetry,
1646     IMAGE_PT_uv_sculpt_brush,
1647     IMAGE_PT_uv_sculpt_curve,
1648     IMAGE_PT_view_histogram,
1649     IMAGE_PT_view_waveform,
1650     IMAGE_PT_view_vectorscope,
1651     IMAGE_PT_sample_line,
1652     IMAGE_PT_scope_sample,
1653     IMAGE_PT_uv_cursor,
1654     IMAGE_PT_grease_pencil,
1655 )
1656
1657
1658 if __name__ == "__main__":  # only for live edit.
1659     from bpy.utils import register_class
1660     for cls in classes:
1661         register_class(cls)