1 # SPDX-License-Identifier: GPL-2.0-or-later
5 """User interface imports and preferences for the addon."""
8 # from time import sleep
12 from bpy
.app
.handlers
import persistent
13 from pathlib
import Path
15 # from bpy.utils import register_class, unregister_class
16 # from bpy.types import (
29 # from bl_operators.presets import AddPresetBase
37 shading_nodes
, # for POV specific nodes
43 # ------------ POV-Centric WORKSPACE ------------ #
45 def pov_centric_moray_like_workspace(dummy
):
46 """Set up a POV centric Workspace if addon was activated and saved as default renderer.
48 This would bring a ’_RestrictData’ error because UI needs to be fully loaded before
49 workspace changes so registering this function in bpy.app.handlers is needed.
50 By default handlers are freed when loading new files, but here we want the handler
51 to stay running across multiple files as part of this add-on. That is why the
52 bpy.app.handlers.persistent decorator is used (@persistent) above.
54 # Scripting workspace may have been altered from factory though, so should
55 # we put all within a Try... Except AttributeErrors ? Any better solution ?
56 # Should it simply not run when opening existing file? be a preferences operator to create
57 # Moray like workspace
59 available_workspaces
= bpy
.data
.workspaces
61 if all(tabs
in available_workspaces
for tabs
in ['POV-Mo', 'POV-Ed']):
62 print("\nPOV-Mo and POV-Ed tabs respectively provide GUI and TEXT\n"
63 "oriented POV workspaces akin to Moray and POVWIN")
65 if 'POV-Ed'not in available_workspaces
:
67 "\nTo use POV centric workspaces you can set POV render option\n"
68 "and save it with File > Defaults > Save Startup File menu"
71 if all(othertabs
not in available_workspaces
for othertabs
in ['Geometry Nodes', 'POV-Ed']):
72 bpy
.ops
.workspace
.append_activate(
73 idname
='Geometry Nodes',
74 filepath
=os
.path
.join(bpy
.utils
.user_resource('CONFIG'), 'startup.blend')
76 except BaseException
as e
:
78 print('An exception occurred: {}'.format(e
))
80 # Last resort: try to import from the blender templates
81 for p
in Path(next(bpy
.utils
.app_template_paths())).rglob("startup.blend"):
82 bpy
.ops
.workspace
.append_activate(
83 idname
=self
.targetWorkspace
,
85 except BaseException
as e
:
87 print('An exception occurred: {}'.format(e
))
88 # Giving up as prerequisites can't be found
90 "\nFactory Geometry Nodes workspace needed for POV text centric"
91 "\nworkspace to activate when POV is set as default renderer"
94 # Create POVWIN like editor (text oriented editing)
95 if 'POV-Ed' not in available_workspaces
and 'Geometry Nodes' in available_workspaces
:
96 wsp
= available_workspaces
.get('Geometry Nodes')
98 if context
.scene
.render
.engine
== 'POVRAY_RENDER' and wsp
is not None:
99 bpy
.ops
.workspace
.duplicate({'workspace': wsp
})
100 available_workspaces
['Geometry Nodes.001'].name
= 'POV-Ed'
101 # May be already done, but explicitly make this workspace the active one
102 context
.window
.workspace
= available_workspaces
['POV-Ed']
103 pov_screen
= available_workspaces
['POV-Ed'].screens
[0]
104 pov_workspace
= pov_screen
.areas
105 pov_window
= context
.window
106 # override = bpy.context.copy() # crashes
108 properties_area
= pov_workspace
[0]
109 nodes_to_3dview_area
= pov_workspace
[1]
110 view3d_to_text_area
= pov_workspace
[2]
111 spreadsheet_to_console_area
= pov_workspace
[3]
114 nodes_to_3dview_area
.ui_type
= 'VIEW_3D'
115 override
['window'] = pov_window
116 override
['screen'] = bpy
.context
.screen
117 override
['area'] = nodes_to_3dview_area
118 override
['region'] = nodes_to_3dview_area
.regions
[-1]
119 bpy
.ops
.screen
.space_type_set_or_cycle(
120 override
, 'INVOKE_DEFAULT', space_type
='VIEW_3D'
122 space
= nodes_to_3dview_area
.spaces
.active
123 space
.region_3d
.view_perspective
= 'CAMERA'
125 override
['window'] = pov_window
126 override
['screen'] = bpy
.context
.screen
127 override
['area'] = view3d_to_text_area
128 override
['region'] = view3d_to_text_area
.regions
[-1]
129 override
['scene'] = bpy
.context
.scene
130 override
['space_data'] = view3d_to_text_area
.spaces
.active
131 bpy
.ops
.screen
.space_type_set_or_cycle(
132 override
, 'INVOKE_DEFAULT', space_type
='TEXT_EDITOR'
134 view3d_to_text_area
.spaces
.active
.show_region_ui
= True
136 spreadsheet_to_console_area
.ui_type
= 'CONSOLE'
137 override
['window'] = pov_window
138 override
['screen'] = bpy
.context
.screen
139 override
['area'] = spreadsheet_to_console_area
140 override
['region'] = spreadsheet_to_console_area
.regions
[-1]
141 bpy
.ops
.screen
.space_type_set_or_cycle(
142 override
, 'INVOKE_DEFAULT', space_type
='CONSOLE'
144 space
= properties_area
.spaces
.active
145 space
.context
= 'RENDER'
146 bpy
.ops
.workspace
.reorder_to_front({'workspace': available_workspaces
['POV-Ed']})
147 except AttributeError:
148 # In case necessary area types lack in existing blend files
151 if 'POV-Mo'not in available_workspaces
:
153 if all(tab
not in available_workspaces
for tab
in ['Rendering', 'POV-Mo']):
154 bpy
.ops
.workspace
.append_activate(
156 filepath
=os
.path
.join(bpy
.utils
.user_resource('CONFIG'), 'startup.blend')
158 except BaseException
as e
:
160 print('An exception occurred: {}'.format(e
))
162 # Last resort: try to import from the blender templates
163 for p
in Path(next(bpy
.utils
.app_template_paths())).rglob("startup.blend"):
164 bpy
.ops
.workspace
.append_activate(
165 idname
=self
.targetWorkspace
,
167 except BaseException
as e
:
169 print('An exception occurred: {}'.format(e
))
172 "\nFactory 'Rendering' workspace needed for POV GUI centric"
173 "\nworkspace to activate when POV is set as default renderer"
176 # Create Moray like workspace (GUI oriented editing)
177 if 'POV-Mo' not in available_workspaces
and 'Rendering' in available_workspaces
:
178 wsp1
= available_workspaces
.get('Rendering')
179 context
= bpy
.context
180 if context
.scene
.render
.engine
== 'POVRAY_RENDER' and wsp1
is not None:
181 bpy
.ops
.workspace
.duplicate({'workspace': wsp1
})
182 available_workspaces
['Rendering.001'].name
= 'POV-Mo'
183 # Already done it would seem, but explicitly make this workspace the active one
184 context
.window
.workspace
= available_workspaces
['POV-Mo']
185 pov_screen
= available_workspaces
['POV-Mo'].screens
[0]
186 pov_workspace
= pov_screen
.areas
187 pov_window
= context
.window
188 # override = bpy.context.copy() # crashes
190 properties_area
= pov_workspace
[0]
191 image_editor_to_view3d_area
= pov_workspace
[2]
194 image_editor_to_view3d_area
.ui_type
= 'VIEW_3D'
195 override
['window'] = pov_window
196 override
['screen'] = bpy
.context
.screen
197 override
['area'] = image_editor_to_view3d_area
198 override
['region'] = image_editor_to_view3d_area
.regions
[-1]
199 bpy
.ops
.screen
.space_type_set_or_cycle(
200 override
, 'INVOKE_DEFAULT', space_type
='VIEW_3D'
202 space
= image_editor_to_view3d_area
.spaces
.active
# Uncomment For non quad view
203 space
.region_3d
.view_perspective
= 'CAMERA' # Uncomment For non quad view
204 space
.show_region_toolbar
= True
205 # bpy.ops.view3d.camera_to_view(override) # Uncomment For non quad view ?
206 for num
, reg
in enumerate(image_editor_to_view3d_area
.regions
):
207 if reg
.type != 'view3d':
208 override
['region'] = image_editor_to_view3d_area
.regions
[num
]
209 bpy
.ops
.screen
.region_quadview(override
) # Comment out for non quad
210 propspace
= properties_area
.spaces
.active
211 propspace
.context
= 'MATERIAL'
212 bpy
.ops
.workspace
.reorder_to_front({'workspace': available_workspaces
['POV-Mo']})
213 except (AttributeError, TypeError):
214 # In case necessary types lack in existing blend files
216 # available_workspaces.update()
218 # -----------------------------------UTF-8---------------------------------- #
219 # Check and fix all strings in current .blend file to be valid UTF-8 Unicode
220 # sometimes needed for old, 2.4x / 2.6x area files
222 bpy
.ops
.wm
.blend_strings_utf8_validate()
223 except BaseException
as e
:
225 print('An exception occurred: {}'.format(e
))
229 def check_material(mat
):
230 """Allow use of material properties buttons rather than nodes."""
233 return not mat
.node_tree
238 def simple_material(mat
):
239 """Test if a material is nodeless."""
240 return (mat
is not None) and (not mat
.use_nodes
)
243 def pov_context_texblock(context
):
244 """Recreate texture context type as deprecated in blender 2.8."""
245 idblock
= context
.brush
246 if idblock
and context
.scene
.texture_context
== 'OTHER':
249 # idblock = bpy.context.active_object.active_material
250 idblock
= context
.view_layer
.objects
.active
.active_material
251 if idblock
and context
.scene
.texture_context
== 'MATERIAL':
254 idblock
= context
.scene
.world
255 if idblock
and context
.scene
.texture_context
== 'WORLD':
258 idblock
= context
.light
259 if idblock
and context
.scene
.texture_context
== 'LIGHT':
262 if context
.particle_system
and context
.scene
.texture_context
== 'PARTICLES':
263 idblock
= context
.particle_system
.settings
266 idblock
= context
.line_style
267 if idblock
and context
.scene
.texture_context
== 'LINESTYLE':
271 # class TextureTypePanel(TextureButtonsPanel):
274 # def poll(cls, context):
275 # tex = context.texture
276 # engine = context.scene.render.engine
277 # return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES))
281 update_files
.register()
282 render_gui
.register()
283 scenography_gui
.register()
284 object_gui
.register()
285 shading_gui
.register()
286 texturing_gui
.register()
287 shading_nodes
.register()
288 scripting_gui
.register()
290 if pov_centric_moray_like_workspace
not in bpy
.app
.handlers
.load_post
:
291 bpy
.app
.handlers
.load_post
.append(pov_centric_moray_like_workspace
)
295 if pov_centric_moray_like_workspace
in bpy
.app
.handlers
.load_post
:
296 bpy
.app
.handlers
.load_post
.remove(pov_centric_moray_like_workspace
)
298 scripting_gui
.unregister()
299 shading_nodes
.unregister()
300 texturing_gui
.unregister()
301 shading_gui
.unregister()
302 object_gui
.unregister()
303 scenography_gui
.unregister()
304 render_gui
.unregister()
305 update_files
.unregister()