space_image.py 53 KB

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