fdc5be4db8d75a32a6331e51596e149500586847
[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 import bpy
21 from bpy.types import Header, Menu, Panel
22 from bl_ui.properties_paint_common import (
23         UnifiedPaintPanel,
24         brush_texture_settings,
25         brush_mask_texture_settings,
26         )
27 from bpy.app.translations import pgettext_iface as iface_
28
29
30 class ImagePaintPanel(UnifiedPaintPanel):
31     bl_space_type = 'IMAGE_EDITOR'
32     bl_region_type = 'UI'
33
34
35 class BrushButtonsPanel:
36     bl_space_type = 'IMAGE_EDITOR'
37     bl_region_type = 'UI'
38
39     @classmethod
40     def poll(cls, context):
41         sima = context.space_data
42         toolsettings = context.tool_settings.image_paint
43         return sima.show_paint and toolsettings.brush
44
45
46 class IMAGE_MT_view(Menu):
47     bl_label = "View"
48
49     def draw(self, context):
50         layout = self.layout
51
52         sima = context.space_data
53         uv = sima.uv_editor
54         toolsettings = context.tool_settings
55
56         show_uvedit = sima.show_uvedit
57         show_render = sima.show_render
58
59         layout.operator("image.properties", icon='MENU_PANEL')
60         layout.operator("image.scopes", icon='MENU_PANEL')
61
62         layout.separator()
63
64         layout.prop(sima, "use_realtime_update")
65         if show_uvedit:
66             layout.prop(toolsettings, "show_uv_local_view")
67
68         layout.prop(uv, "show_other_objects")
69
70         layout.separator()
71
72         layout.operator("image.view_zoom_in")
73         layout.operator("image.view_zoom_out")
74
75         layout.separator()
76
77         ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1))
78
79         for a, b in ratios:
80             layout.operator("image.view_zoom_ratio", text=iface_("Zoom %d:%d") % (a, b), translate=False).ratio = a / b
81
82         layout.separator()
83
84         if show_uvedit:
85             layout.operator("image.view_selected")
86
87         layout.operator("image.view_all")
88
89         layout.separator()
90
91         if show_render:
92             layout.operator("image.cycle_render_slot", text="Render Slot Cycle Next")
93             layout.operator("image.cycle_render_slot", text="Render Slot Cycle Previous").reverse = True
94             layout.separator()
95
96         layout.operator("screen.area_dupli")
97         layout.operator("screen.screen_full_area")
98
99
100 class IMAGE_MT_select(Menu):
101     bl_label = "Select"
102
103     def draw(self, context):
104         layout = self.layout
105
106         layout.operator("uv.select_border").pinned = False
107         layout.operator("uv.select_border", text="Border Select Pinned").pinned = True
108
109         layout.separator()
110
111         layout.operator("uv.select_all").action = 'TOGGLE'
112         layout.operator("uv.select_all", text="Inverse").action = 'INVERT'
113
114         layout.separator()
115
116         layout.operator("uv.select_pinned")
117         layout.operator("uv.select_linked")
118
119         layout.separator()
120
121         layout.operator("uv.select_less", text="Less")
122         layout.operator("uv.select_more", text="More")
123
124         layout.separator()
125
126         layout.operator("uv.select_split")
127
128
129 class IMAGE_MT_image(Menu):
130     bl_label = "Image"
131
132     def draw(self, context):
133         layout = self.layout
134
135         sima = context.space_data
136         ima = sima.image
137
138         layout.operator("image.new")
139         layout.operator("image.open")
140
141         show_render = sima.show_render
142
143         if ima:
144             if not show_render:
145                 layout.operator("image.replace")
146                 layout.operator("image.reload")
147
148             layout.operator("image.save")
149             layout.operator("image.save_as")
150             layout.operator("image.save_as", text="Save a Copy").copy = True
151
152             if ima.source == 'SEQUENCE':
153                 layout.operator("image.save_sequence")
154
155             layout.operator("image.external_edit", "Edit Externally")
156
157             layout.separator()
158
159             layout.menu("IMAGE_MT_image_invert")
160
161             if not show_render:
162                 layout.separator()
163
164                 if not ima.packed_file:
165                     layout.operator("image.pack")
166
167                 # only for dirty && specific image types, perhaps
168                 # this could be done in operator poll too
169                 if ima.is_dirty:
170                     if ima.source in {'FILE', 'GENERATED'} and ima.type != 'OPEN_EXR_MULTILAYER':
171                         layout.operator("image.pack", text="Pack As PNG").as_png = True
172
173             layout.separator()
174
175
176 class IMAGE_MT_image_invert(Menu):
177     bl_label = "Invert"
178
179     def draw(self, context):
180         layout = self.layout
181
182         props = layout.operator("image.invert", text="Invert Image Colors")
183         props.invert_r = True
184         props.invert_g = True
185         props.invert_b = True
186
187         layout.separator()
188
189         layout.operator("image.invert", text="Invert Red Channel").invert_r = True
190         layout.operator("image.invert", text="Invert Green Channel").invert_g = True
191         layout.operator("image.invert", text="Invert Blue Channel").invert_b = True
192         layout.operator("image.invert", text="Invert Alpha Channel").invert_a = True
193
194
195 class IMAGE_MT_uvs_showhide(Menu):
196     bl_label = "Show/Hide Faces"
197
198     def draw(self, context):
199         layout = self.layout
200
201         layout.operator("uv.reveal")
202         layout.operator("uv.hide", text="Hide Selected").unselected = False
203         layout.operator("uv.hide", text="Hide Unselected").unselected = True
204
205
206 class IMAGE_MT_uvs_transform(Menu):
207     bl_label = "Transform"
208
209     def draw(self, context):
210         layout = self.layout
211
212         layout.operator("transform.translate")
213         layout.operator("transform.rotate")
214         layout.operator("transform.resize")
215
216         layout.separator()
217
218         layout.operator("transform.shear")
219
220
221 class IMAGE_MT_uvs_snap(Menu):
222     bl_label = "Snap"
223
224     def draw(self, context):
225         layout = self.layout
226
227         layout.operator_context = 'EXEC_REGION_WIN'
228
229         layout.operator("uv.snap_selected", text="Selected to Pixels").target = 'PIXELS'
230         layout.operator("uv.snap_selected", text="Selected to Cursor").target = 'CURSOR'
231         layout.operator("uv.snap_selected", text="Selected to Cursor (Offset)").target = 'CURSOR_OFFSET'
232         layout.operator("uv.snap_selected", text="Selected to Adjacent Unselected").target = 'ADJACENT_UNSELECTED'
233
234         layout.separator()
235
236         layout.operator("uv.snap_cursor", text="Cursor to Pixels").target = 'PIXELS'
237         layout.operator("uv.snap_cursor", text="Cursor to Selected").target = 'SELECTED'
238
239
240 class IMAGE_MT_uvs_mirror(Menu):
241     bl_label = "Mirror"
242
243     def draw(self, context):
244         layout = self.layout
245
246         layout.operator_context = 'EXEC_REGION_WIN'
247
248         layout.operator("transform.mirror", text="X Axis").constraint_axis[0] = True
249         layout.operator("transform.mirror", text="Y Axis").constraint_axis[1] = True
250
251
252 class IMAGE_MT_uvs_weldalign(Menu):
253     bl_label = "Weld/Align"
254
255     def draw(self, context):
256         layout = self.layout
257
258         layout.operator("uv.weld")  # W, 1
259         layout.operator("uv.remove_doubles")
260         layout.operator_enum("uv.align", "axis")  # W, 2/3/4
261
262
263 class IMAGE_MT_uvs(Menu):
264     bl_label = "UVs"
265
266     def draw(self, context):
267         layout = self.layout
268
269         sima = context.space_data
270         uv = sima.uv_editor
271         toolsettings = context.tool_settings
272
273         layout.prop(uv, "use_snap_to_pixels")
274         layout.prop(uv, "lock_bounds")
275
276         layout.separator()
277
278         layout.prop(toolsettings, "use_uv_sculpt")
279
280         layout.separator()
281
282         layout.prop(uv, "use_live_unwrap")
283         layout.operator("uv.unwrap")
284         layout.operator("uv.pin", text="Unpin").clear = True
285         layout.operator("uv.pin")
286
287         layout.separator()
288
289         layout.operator("uv.pack_islands")
290         layout.operator("uv.average_islands_scale")
291         layout.operator("uv.minimize_stretch")
292         layout.operator("uv.stitch")
293         layout.operator("uv.mark_seam")
294         layout.operator("uv.seams_from_islands")
295         layout.operator("mesh.faces_mirror_uv")
296
297         layout.separator()
298
299         layout.menu("IMAGE_MT_uvs_transform")
300         layout.menu("IMAGE_MT_uvs_mirror")
301         layout.menu("IMAGE_MT_uvs_snap")
302         layout.menu("IMAGE_MT_uvs_weldalign")
303
304         layout.separator()
305
306         layout.prop_menu_enum(toolsettings, "proportional_edit")
307         layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
308
309         layout.separator()
310
311         layout.menu("IMAGE_MT_uvs_showhide")
312
313
314 class IMAGE_MT_uvs_select_mode(Menu):
315     bl_label = "UV Select Mode"
316
317     def draw(self, context):
318         layout = self.layout
319
320         layout.operator_context = 'INVOKE_REGION_WIN'
321         toolsettings = context.tool_settings
322
323         # do smart things depending on whether uv_select_sync is on
324
325         if toolsettings.use_uv_select_sync:
326             props = layout.operator("wm.context_set_value", text="Vertex", icon='VERTEXSEL')
327             props.value = "(True, False, False)"
328             props.data_path = "tool_settings.mesh_select_mode"
329
330             props = layout.operator("wm.context_set_value", text="Edge", icon='EDGESEL')
331             props.value = "(False, True, False)"
332             props.data_path = "tool_settings.mesh_select_mode"
333
334             props = layout.operator("wm.context_set_value", text="Face", icon='FACESEL')
335             props.value = "(False, False, True)"
336             props.data_path = "tool_settings.mesh_select_mode"
337
338         else:
339             props = layout.operator("wm.context_set_string", text="Vertex", icon='UV_VERTEXSEL')
340             props.value = 'VERTEX'
341             props.data_path = "tool_settings.uv_select_mode"
342
343             props = layout.operator("wm.context_set_string", text="Edge", icon='UV_EDGESEL')
344             props.value = 'EDGE'
345             props.data_path = "tool_settings.uv_select_mode"
346
347             props = layout.operator("wm.context_set_string", text="Face", icon='UV_FACESEL')
348             props.value = 'FACE'
349             props.data_path = "tool_settings.uv_select_mode"
350
351             props = layout.operator("wm.context_set_string", text="Island", icon='UV_ISLANDSEL')
352             props.value = 'ISLAND'
353             props.data_path = "tool_settings.uv_select_mode"
354
355
356 class IMAGE_HT_header(Header):
357     bl_space_type = 'IMAGE_EDITOR'
358
359     def draw(self, context):
360         layout = self.layout
361
362         sima = context.space_data
363         ima = sima.image
364         iuser = sima.image_user
365         toolsettings = context.tool_settings
366         mode = sima.mode
367
368         show_render = sima.show_render
369         # show_paint = sima.show_paint
370         show_uvedit = sima.show_uvedit
371         show_maskedit = sima.show_maskedit
372
373         row = layout.row(align=True)
374         row.template_header()
375
376         MASK_MT_editor_menus.draw_collapsible(context, layout)
377
378         layout.template_ID(sima, "image", new="image.new", open="image.open")
379         if not show_render:
380             layout.prop(sima, "use_image_pin", text="")
381
382         layout.prop(sima, "mode", text="")
383
384         if show_maskedit:
385             row = layout.row()
386             row.template_ID(sima, "mask", new="mask.new")
387
388         if show_uvedit or show_maskedit:
389             layout.prop(sima, "pivot_point", icon_only=True)
390
391         # uv editing
392         if show_uvedit:
393             uvedit = sima.uv_editor
394
395             layout.prop(toolsettings, "use_uv_select_sync", text="")
396
397             if toolsettings.use_uv_select_sync:
398                 layout.template_edit_mode_selection()
399             else:
400                 layout.prop(toolsettings, "uv_select_mode", text="", expand=True)
401                 layout.prop(uvedit, "sticky_select_mode", icon_only=True)
402
403             row = layout.row(align=True)
404             row.prop(toolsettings, "proportional_edit", icon_only=True)
405             if toolsettings.proportional_edit != 'DISABLED':
406                 row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
407
408             row = layout.row(align=True)
409             row.prop(toolsettings, "use_snap", text="")
410             row.prop(toolsettings, "snap_uv_element", icon_only=True)
411             if toolsettings.snap_uv_element != 'INCREMENT':
412                 row.prop(toolsettings, "snap_target", text="")
413
414             mesh = context.edit_object.data
415             layout.prop_search(mesh.uv_textures, "active", mesh, "uv_textures", text="")
416
417         if ima:
418             # layers
419             layout.template_image_layers(ima, iuser)
420
421             # draw options
422             row = layout.row(align=True)
423             row.prop(sima, "draw_channels", text="", expand=True)
424
425             row = layout.row(align=True)
426             if ima.type == 'COMPOSITE':
427                 row.operator("image.record_composite", icon='REC')
428             if ima.type == 'COMPOSITE' and ima.source in {'MOVIE', 'SEQUENCE'}:
429                 row.operator("image.play_composite", icon='PLAY')
430
431         if show_uvedit or show_maskedit or mode == 'PAINT':
432             layout.prop(sima, "use_realtime_update", icon_only=True, icon='LOCKED')
433
434
435 class MASK_MT_editor_menus(Menu):
436     bl_idname = "MASK_MT_editor_menus"
437     bl_label = ""
438
439     def draw(self, context):
440         self.draw_menus(self.layout, context)
441
442     @staticmethod
443     def draw_menus(layout, context):
444         sima = context.space_data
445         ima = sima.image
446
447         show_render = sima.show_render
448         show_uvedit = sima.show_uvedit
449         show_maskedit = sima.show_maskedit
450
451         layout.menu("IMAGE_MT_view")
452
453         if show_uvedit:
454             layout.menu("IMAGE_MT_select")
455         if show_maskedit:
456             layout.menu("MASK_MT_select")
457
458         if ima and ima.is_dirty:
459             layout.menu("IMAGE_MT_image", text="Image*")
460         else:
461             layout.menu("IMAGE_MT_image", text="Image")
462
463         if show_uvedit:
464             layout.menu("IMAGE_MT_uvs")
465         if show_maskedit:
466             layout.menu("MASK_MT_mask")
467
468
469 class IMAGE_PT_image_properties(Panel):
470     bl_space_type = 'IMAGE_EDITOR'
471     bl_region_type = 'UI'
472     bl_label = "Image"
473
474     @classmethod
475     def poll(cls, context):
476         sima = context.space_data
477         return (sima.image)
478
479     def draw(self, context):
480         layout = self.layout
481
482         sima = context.space_data
483         iuser = sima.image_user
484
485         layout.template_image(sima, "image", iuser)
486
487
488 class IMAGE_PT_game_properties(Panel):
489     bl_space_type = 'IMAGE_EDITOR'
490     bl_region_type = 'UI'
491     bl_label = "Game Properties"
492
493     @classmethod
494     def poll(cls, context):
495         sima = context.space_data
496         # display even when not in game mode because these settings effect the 3d view
497         return (sima and sima.image)  # and (rd.engine == 'BLENDER_GAME')
498
499     def draw(self, context):
500         layout = self.layout
501
502         sima = context.space_data
503         ima = sima.image
504
505         split = layout.split()
506
507         col = split.column()
508         col.prop(ima, "use_animation")
509         sub = col.column(align=True)
510         sub.active = ima.use_animation
511         sub.prop(ima, "frame_start", text="Start")
512         sub.prop(ima, "frame_end", text="End")
513         sub.prop(ima, "fps", text="Speed")
514
515         col.prop(ima, "use_tiles")
516         sub = col.column(align=True)
517         sub.active = ima.use_tiles or ima.use_animation
518         sub.prop(ima, "tiles_x", text="X")
519         sub.prop(ima, "tiles_y", text="Y")
520
521         col = split.column()
522         col.label(text="Clamp:")
523         col.prop(ima, "use_clamp_x", text="X")
524         col.prop(ima, "use_clamp_y", text="Y")
525         col.separator()
526         col.prop(ima, "mapping", expand=True)
527
528
529 class IMAGE_PT_view_histogram(Panel):
530     bl_space_type = 'IMAGE_EDITOR'
531     bl_region_type = 'PREVIEW'
532     bl_label = "Histogram"
533
534     @classmethod
535     def poll(cls, context):
536         sima = context.space_data
537         return (sima and sima.image)
538
539     def draw(self, context):
540         layout = self.layout
541
542         sima = context.space_data
543         hist = sima.scopes.histogram
544
545         layout.template_histogram(sima.scopes, "histogram")
546         row = layout.row(align=True)
547         row.prop(hist, "mode", expand=True)
548         row.prop(hist, "show_line", text="")
549
550
551 class IMAGE_PT_view_waveform(Panel):
552     bl_space_type = 'IMAGE_EDITOR'
553     bl_region_type = 'PREVIEW'
554     bl_label = "Waveform"
555
556     @classmethod
557     def poll(cls, context):
558         sima = context.space_data
559         return (sima and sima.image)
560
561     def draw(self, context):
562         layout = self.layout
563
564         sima = context.space_data
565
566         layout.template_waveform(sima, "scopes")
567         row = layout.split(percentage=0.75)
568         row.prop(sima.scopes, "waveform_alpha")
569         row.prop(sima.scopes, "waveform_mode", icon_only=True)
570
571
572 class IMAGE_PT_view_vectorscope(Panel):
573     bl_space_type = 'IMAGE_EDITOR'
574     bl_region_type = 'PREVIEW'
575     bl_label = "Vectorscope"
576
577     @classmethod
578     def poll(cls, context):
579         sima = context.space_data
580         return (sima and sima.image)
581
582     def draw(self, context):
583         layout = self.layout
584
585         sima = context.space_data
586         layout.template_vectorscope(sima, "scopes")
587         layout.prop(sima.scopes, "vectorscope_alpha")
588
589
590 class IMAGE_PT_sample_line(Panel):
591     bl_space_type = 'IMAGE_EDITOR'
592     bl_region_type = 'PREVIEW'
593     bl_label = "Sample Line"
594
595     @classmethod
596     def poll(cls, context):
597         sima = context.space_data
598         return (sima and sima.image)
599
600     def draw(self, context):
601         layout = self.layout
602
603         sima = context.space_data
604         hist = sima.sample_histogram
605
606         layout.operator("image.sample_line")
607         layout.template_histogram(sima, "sample_histogram")
608         row = layout.row(align=True)
609         row.prop(hist, "mode", expand=True)
610         row.prop(hist, "show_line", text="")
611
612
613 class IMAGE_PT_scope_sample(Panel):
614     bl_space_type = 'IMAGE_EDITOR'
615     bl_region_type = 'PREVIEW'
616     bl_label = "Scope Samples"
617
618     @classmethod
619     def poll(cls, context):
620         sima = context.space_data
621         return sima
622
623     def draw(self, context):
624         layout = self.layout
625
626         sima = context.space_data
627
628         row = layout.row()
629         row.prop(sima.scopes, "use_full_resolution")
630         sub = row.row()
631         sub.active = not sima.scopes.use_full_resolution
632         sub.prop(sima.scopes, "accuracy")
633
634
635 class IMAGE_PT_view_properties(Panel):
636     bl_space_type = 'IMAGE_EDITOR'
637     bl_region_type = 'UI'
638     bl_label = "Display"
639
640     @classmethod
641     def poll(cls, context):
642         sima = context.space_data
643         return (sima and (sima.image or sima.show_uvedit))
644
645     def draw(self, context):
646         layout = self.layout
647
648         sima = context.space_data
649         ima = sima.image
650         show_uvedit = sima.show_uvedit
651         show_maskedit = sima.show_maskedit
652         uvedit = sima.uv_editor
653
654         split = layout.split()
655
656         col = split.column()
657         if ima:
658             col.prop(ima, "display_aspect", text="Aspect Ratio")
659
660             col = split.column()
661             col.label(text="Coordinates:")
662             col.prop(sima, "show_repeat", text="Repeat")
663             if show_uvedit:
664                 col.prop(uvedit, "show_normalized_coords", text="Normalized")
665
666         elif show_uvedit:
667             col.label(text="Coordinates:")
668             col.prop(uvedit, "show_normalized_coords", text="Normalized")
669
670         if show_uvedit or show_maskedit:
671             col = layout.column()
672             col.label("Cursor Location:")
673             col.row().prop(sima, "cursor_location", text="")
674
675         if show_uvedit:
676             col.separator()
677
678             col.label(text="UVs:")
679             col.row().prop(uvedit, "edge_draw_type", expand=True)
680
681             split = layout.split()
682
683             col = split.column()
684             col.prop(uvedit, "show_faces")
685             col.prop(uvedit, "show_smooth_edges", text="Smooth")
686             col.prop(uvedit, "show_modified_edges", text="Modified")
687
688             col = split.column()
689             col.prop(uvedit, "show_stretch", text="Stretch")
690             sub = col.column()
691             sub.active = uvedit.show_stretch
692             sub.row().prop(uvedit, "draw_stretch_type", expand=True)
693
694
695 class IMAGE_PT_paint(Panel, ImagePaintPanel):
696     bl_space_type = 'IMAGE_EDITOR'
697     bl_region_type = 'UI'
698     bl_label = "Paint"
699
700     @classmethod
701     def poll(cls, context):
702         sima = context.space_data
703         return sima.show_paint
704
705     def draw(self, context):
706         layout = self.layout
707
708         toolsettings = context.tool_settings.image_paint
709         brush = toolsettings.brush
710
711         col = layout.column()
712         col.template_ID_preview(toolsettings, "brush", new="brush.add", rows=2, cols=6)
713
714         if brush:
715             col = layout.column()
716
717             if brush.image_tool == 'DRAW' and brush.blend not in ('ERASE_ALPHA', 'ADD_ALPHA'):
718                 col.template_color_picker(brush, "color", value_slider=True)
719                 col.prop(brush, "color", text="")
720
721             row = col.row(align=True)
722             self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
723             self.prop_unified_size(row, context, brush, "use_pressure_size")
724
725             row = col.row(align=True)
726             self.prop_unified_strength(row, context, brush, "strength", slider=True, text="Strength")
727             self.prop_unified_strength(row, context, brush, "use_pressure_strength")
728
729             col.prop(brush, "blend", text="Blend")
730
731             if brush.image_tool == 'CLONE':
732                 col.separator()
733                 col.prop(brush, "clone_image", text="Image")
734                 col.prop(brush, "clone_alpha", text="Alpha")
735
736
737 class IMAGE_PT_tools_brush_overlay(BrushButtonsPanel, Panel):
738     bl_label = "Overlay"
739     bl_options = {'DEFAULT_CLOSED'}
740
741     def draw(self, context):
742         layout = self.layout
743
744         toolsettings = context.tool_settings.image_paint
745         brush = toolsettings.brush
746         tex_slot = brush.texture_slot
747         tex_slot_mask = brush.mask_texture_slot
748
749         col = layout.column()
750
751         col.label(text="Curve:")
752
753         row = col.row(align=True)
754         if brush.use_cursor_overlay:
755             row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')
756         else:
757             row.prop(brush, "use_cursor_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON')
758
759         sub = row.row(align=True)
760         sub.prop(brush, "cursor_overlay_alpha", text="Alpha")
761         sub.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
762
763         col.active = brush.brush_capabilities.has_overlay
764         col.label(text="Texture:")
765         row = col.row(align=True)
766         if tex_slot.map_mode != 'STENCIL':
767             if brush.use_primary_overlay:
768                 row.prop(brush, "use_primary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')
769             else:
770                 row.prop(brush, "use_primary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON')
771
772         sub = row.row(align=True)
773         sub.prop(brush, "texture_overlay_alpha", text="Alpha")
774         sub.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
775
776         col.label(text="Mask Texture:")
777
778         row = col.row(align=True)
779         if tex_slot_mask.map_mode != 'STENCIL':
780             if brush.use_secondary_overlay:
781                 row.prop(brush, "use_secondary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_OFF')
782             else:
783                 row.prop(brush, "use_secondary_overlay", toggle=True, text="", icon='RESTRICT_VIEW_ON')
784
785         sub = row.row(align=True)
786         sub.prop(brush, "mask_overlay_alpha", text="Alpha")
787         sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
788
789
790 class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel):
791     bl_label = "Texture"
792     bl_options = {'DEFAULT_CLOSED'}
793
794     def draw(self, context):
795         layout = self.layout
796
797         toolsettings = context.tool_settings.image_paint
798         brush = toolsettings.brush
799         tex_slot = brush.texture_slot
800
801         col = layout.column()
802         col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
803
804         brush_texture_settings(col, brush, 0)
805
806
807 class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel):
808     bl_label = "Texture Mask"
809     bl_options = {'DEFAULT_CLOSED'}
810
811     def draw(self, context):
812         layout = self.layout
813
814         brush = context.tool_settings.image_paint.brush
815         tex_slot_alpha = brush.mask_texture_slot
816
817         col = layout.column()
818
819         col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
820
821         brush_mask_texture_settings(col, brush)
822
823
824 class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, Panel):
825     bl_label = "Tool"
826     bl_options = {'DEFAULT_CLOSED'}
827
828     def draw(self, context):
829         layout = self.layout
830         toolsettings = context.tool_settings.image_paint
831         brush = toolsettings.brush
832
833         layout.prop(brush, "image_tool", text="")
834
835         row = layout.row(align=True)
836         row.prop(brush, "use_paint_sculpt", text="", icon='SCULPTMODE_HLT')
837         row.prop(brush, "use_paint_vertex", text="", icon='VPAINT_HLT')
838         row.prop(brush, "use_paint_weight", text="", icon='WPAINT_HLT')
839         row.prop(brush, "use_paint_image", text="", icon='TPAINT_HLT')
840
841
842 class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel):
843     bl_label = "Paint Stroke"
844     bl_options = {'DEFAULT_CLOSED'}
845
846     def draw(self, context):
847         layout = self.layout
848
849         toolsettings = context.tool_settings.image_paint
850         brush = toolsettings.brush
851
852         col = layout.column()
853
854         col.label(text="Stroke Method:")
855
856         col.prop(brush, "stroke_method", text="")
857
858         if brush.use_anchor:
859             col.separator()
860             col.prop(brush, "use_edge_to_edge", "Edge To Edge")
861
862         if brush.use_airbrush:
863             col.separator()
864             col.prop(brush, "rate", text="Rate", slider=True)
865
866         if brush.use_space:
867             col.separator()
868             row = col.row(align=True)
869             row.active = brush.use_space
870             row.prop(brush, "spacing", text="Spacing")
871             row.prop(brush, "use_pressure_spacing", toggle=True, text="")
872
873         col = layout.column()
874         col.separator()
875
876         row = col.row(align=True)
877         row.prop(brush, "use_relative_jitter", icon_only=True)
878         if brush.use_relative_jitter:
879             row.prop(brush, "jitter", slider=True)
880         else:
881             row.prop(brush, "jitter_absolute")
882         row.prop(brush, "use_pressure_jitter", toggle=True, text="")
883
884         col = layout.column()
885         col.separator()
886
887         col.prop(brush, "use_smooth_stroke")
888
889         sub = col.column()
890         sub.active = brush.use_smooth_stroke
891         sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
892         sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
893
894         col.separator()
895
896         col.prop(toolsettings, "input_samples")
897
898         col.separator()
899
900         col.prop(brush, "use_wrap")
901
902
903 class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
904     bl_label = "Paint Curve"
905     bl_options = {'DEFAULT_CLOSED'}
906
907     def draw(self, context):
908         layout = self.layout
909
910         toolsettings = context.tool_settings.image_paint
911         brush = toolsettings.brush
912
913         layout.template_curve_mapping(brush, "curve")
914
915         row = layout.row(align=True)
916         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
917         row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
918         row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
919         row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
920         row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
921         row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
922
923
924 class IMAGE_PT_tools_brush_appearance(BrushButtonsPanel, Panel):
925     bl_label = "Appearance"
926     bl_options = {'DEFAULT_CLOSED'}
927
928     def draw(self, context):
929         layout = self.layout
930
931         toolsettings = context.tool_settings.image_paint
932         brush = toolsettings.brush
933
934         if brush is None:  # unlikely but can happen
935             layout.label(text="Brush Unset")
936             return
937
938         col = layout.column()
939         col.prop(toolsettings, "show_brush")
940
941         col = col.column()
942         col.prop(brush, "cursor_color_add", text="")
943         col.active = toolsettings.show_brush
944
945         layout.separator()
946
947         col = layout.column(align=True)
948         col.prop(brush, "use_custom_icon")
949         if brush.use_custom_icon:
950             col.prop(brush, "icon_filepath", text="")
951
952
953 class IMAGE_UV_sculpt_curve(Panel):
954     bl_space_type = 'IMAGE_EDITOR'
955     bl_region_type = 'UI'
956     bl_label = "UV Sculpt Curve"
957     bl_options = {'DEFAULT_CLOSED'}
958
959     @classmethod
960     def poll(cls, context):
961         sima = context.space_data
962         toolsettings = context.tool_settings.image_paint
963         return sima.show_uvedit and context.tool_settings.use_uv_sculpt and not (sima.show_paint and toolsettings.brush)
964
965     def draw(self, context):
966         layout = self.layout
967
968         toolsettings = context.tool_settings
969         uvsculpt = toolsettings.uv_sculpt
970         brush = uvsculpt.brush
971
972         layout.template_curve_mapping(brush, "curve")
973
974         row = layout.row(align=True)
975         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
976         row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
977         row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
978         row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
979         row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
980         row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
981
982
983 class IMAGE_UV_sculpt(Panel, ImagePaintPanel):
984     bl_space_type = 'IMAGE_EDITOR'
985     bl_region_type = 'UI'
986     bl_label = "UV Sculpt"
987
988     @classmethod
989     def poll(cls, context):
990         sima = context.space_data
991         toolsettings = context.tool_settings.image_paint
992         return sima.show_uvedit and context.tool_settings.use_uv_sculpt and not (sima.show_paint and toolsettings.brush)
993
994     def draw(self, context):
995         layout = self.layout
996
997         toolsettings = context.tool_settings
998         uvsculpt = toolsettings.uv_sculpt
999         brush = uvsculpt.brush
1000
1001         if brush:
1002             col = layout.column()
1003
1004             row = col.row(align=True)
1005             self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
1006             self.prop_unified_size(row, context, brush, "use_pressure_size")
1007
1008             row = col.row(align=True)
1009             self.prop_unified_strength(row, context, brush, "strength", slider=True, text="Strength")
1010             self.prop_unified_strength(row, context, brush, "use_pressure_strength")
1011
1012         col = layout.column()
1013         col.prop(toolsettings, "uv_sculpt_lock_borders")
1014         col.prop(toolsettings, "uv_sculpt_all_islands")
1015         col.prop(toolsettings, "uv_sculpt_tool")
1016
1017         if toolsettings.uv_sculpt_tool == 'RELAX':
1018             col.prop(toolsettings, "uv_relax_method")
1019
1020
1021 # -----------------------------------------------------------------------------
1022 # Mask (similar code in space_clip.py, keep in sync)
1023 # note! - panel placement does _not_ fit well with image panels... need to fix
1024
1025 from bl_ui.properties_mask_common import (MASK_PT_mask,
1026                                           MASK_PT_layers,
1027                                           MASK_PT_spline,
1028                                           MASK_PT_point,
1029                                           MASK_PT_display,
1030                                           MASK_PT_tools)
1031
1032
1033 class IMAGE_PT_mask(MASK_PT_mask, Panel):
1034     bl_space_type = 'IMAGE_EDITOR'
1035     bl_region_type = 'PREVIEW'
1036
1037
1038 class IMAGE_PT_mask_layers(MASK_PT_layers, Panel):
1039     bl_space_type = 'IMAGE_EDITOR'
1040     bl_region_type = 'PREVIEW'
1041
1042
1043 class IMAGE_PT_mask_display(MASK_PT_display, Panel):
1044     bl_space_type = 'IMAGE_EDITOR'
1045     bl_region_type = 'PREVIEW'
1046
1047
1048 class IMAGE_PT_active_mask_spline(MASK_PT_spline, Panel):
1049     bl_space_type = 'IMAGE_EDITOR'
1050     bl_region_type = 'PREVIEW'
1051
1052
1053 class IMAGE_PT_active_mask_point(MASK_PT_point, Panel):
1054     bl_space_type = 'IMAGE_EDITOR'
1055     bl_region_type = 'PREVIEW'
1056
1057
1058 class IMAGE_PT_tools_mask(MASK_PT_tools, Panel):
1059     bl_space_type = 'IMAGE_EDITOR'
1060     bl_region_type = 'UI'  # is 'TOOLS' in the clip editor
1061
1062 # --- end mask ---
1063
1064 if __name__ == "__main__":  # only for live edit.
1065     bpy.utils.register_module(__name__)