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