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