1 # SPDX-License-Identifier: GPL-2.0-or-later
4 """User interface to POV Scene Description Language snippets or full includes:
6 import, load, create or edit """
9 from bpy
.utils
import register_class
, unregister_class
10 from bpy
.types
import Operator
, Menu
, Panel
11 from sys
import platform
# really import here, as in ui.py and in render.py?
12 import os
# really import here and in render.py?
13 from os
.path
import isfile
17 """POV can be installed with some include files.
19 Get their path as defined in user preferences or registry keys for
20 the user to be able to invoke them."""
22 addon_prefs
= bpy
.context
.preferences
.addons
[__package__
].preferences
23 # Use the system preference if its set.
24 pov_documents
= addon_prefs
.docpath_povray
26 if os
.path
.exists(pov_documents
):
28 # Implicit else, as here return was still not triggered:
30 "User Preferences path to povray documents %r NOT FOUND, checking $PATH" % pov_documents
34 if platform
.startswith('win'):
38 win_reg_key
= winreg
.OpenKey(
39 winreg
.HKEY_CURRENT_USER
, "Software\\POV-Ray\\v3.7\\Windows"
41 win_docpath
= winreg
.QueryValueEx(win_reg_key
, "DocPath")[0]
42 pov_documents
= os
.path
.join(win_docpath
, "Insert Menu")
43 if os
.path
.exists(pov_documents
):
45 except FileNotFoundError
:
47 # search the path all os's
48 pov_documents_default
= "include"
50 os_path_ls
= os
.getenv("PATH").split(':') + [""]
52 for dir_name
in os_path_ls
:
53 pov_documents
= os
.path
.join(dir_name
, pov_documents_default
)
54 if os
.path
.exists(pov_documents
):
59 # ---------------------------------------------------------------- #
62 class TextButtonsPanel
:
63 """Use this class to define buttons from the side tab of
66 bl_space_type
= 'TEXT_EDITOR'
69 COMPAT_ENGINES
= {'POVRAY_RENDER'}
72 def poll(cls
, context
):
73 text
= context
.space_data
74 rd
= context
.scene
.render
75 return text
and (rd
.engine
in cls
.COMPAT_ENGINES
)
78 # ---------------------------------------------------------------- #
79 # Text Povray Settings
80 # ---------------------------------------------------------------- #
83 class TEXT_OT_POV_insert(Operator
):
84 """Create blender text editor operator to insert pov snippets like other pov IDEs"""
86 bl_idname
= "text.povray_insert"
89 filepath
: bpy
.props
.StringProperty(name
="Filepath", subtype
='FILE_PATH')
92 def poll(cls
, context
):
93 text
= context
.space_data
.text
94 return context
.area
.type == 'TEXT_EDITOR' and text
is not None
95 # return bpy.ops.text.insert.poll() this Bpy op has no poll()
97 def execute(self
, context
):
98 if self
.filepath
and isfile(self
.filepath
):
99 with
open(self
.filepath
, "r") as file:
100 bpy
.ops
.text
.insert(text
=file.read())
102 # places the cursor at the end without scrolling -.-
103 # context.space_data.text.write(file.read())
109 def validinsert(ext
):
110 """Since preview images could be in same folder, filter only insertable text"""
111 return ext
in {".txt", ".inc", ".pov"}
114 class TEXT_MT_POV_insert(Menu
):
115 """Create a menu launcher in text editor for the TEXT_OT_POV_insert operator ."""
118 bl_idname
= "TEXT_MT_POV_insert"
120 def draw(self
, context
):
121 pov_documents
= locate_docpath()
122 prop
= self
.layout
.operator("wm.path_open", text
="Open folder", icon
='FILE_FOLDER')
123 prop
.filepath
= pov_documents
124 self
.layout
.separator()
126 # todo: structure submenus by dir
127 pov_insert_items_list
= [root
for root
, dirs
, files
in os
.walk(pov_documents
)]
128 print(pov_insert_items_list
)
130 pov_insert_items_list
,
131 "text.povray_insert",
132 # {"internal": True},
133 filter_ext
=validinsert
,
137 class TEXT_PT_POV_custom_code(TextButtonsPanel
, Panel
):
138 """Use this class to create a panel in text editor for the user to decide if he renders text
140 only or adds to 3d scene."""
143 COMPAT_ENGINES
= {'POVRAY_RENDER'}
145 def draw(self
, context
):
148 text
= context
.space_data
.text
150 pov_documents
= locate_docpath()
151 if not pov_documents
:
152 layout
.label(text
="Please configure ", icon
="INFO")
153 layout
.label(text
="default pov include path ")
154 layout
.label(text
="in addon preferences")
157 "preferences.addon_show",
158 text
="Go to Render: Persistence of Vision addon",
160 ).module
= "render_povray"
164 # print(pov_documents)
165 layout
.menu(TEXT_MT_POV_insert
.bl_idname
)
169 box
.label(text
='Source to render:', icon
='RENDER_STILL')
171 row
.prop(text
.pov
, "custom_code", expand
=True)
172 if text
.pov
.custom_code
in {'3dview'}:
173 box
.operator("render.render", icon
='OUTLINER_DATA_ARMATURE')
174 if text
.pov
.custom_code
in {'text'}:
175 rtext
= bpy
.context
.space_data
.text
# is r a typo ? or why written, not used
176 box
.operator("text.run", icon
='ARMATURE_DATA')
177 # layout.prop(text.pov, "custom_code")
178 elif text
.pov
.custom_code
in {'both'}:
179 box
.operator("render.render", icon
='POSE_HLT')
180 layout
.label(text
="Please specify declared", icon
="INFO")
181 layout
.label(text
="items in properties ")
182 # layout.label(text="")
183 layout
.label(text
="replacement fields")
186 # ---------------------------------------------------------------- #
187 # Text editor templates from header menu
190 class TEXT_MT_POV_templates(Menu
):
191 """Use this class to create a menu for the same pov templates scenes as other pov IDEs."""
195 # We list templates on file evaluation, we can assume they are static data,
196 # and better avoid running this on every draw call.
197 template_paths
= [os
.path
.join(os
.path
.dirname(__file__
), "templates_pov")]
199 def draw(self
, context
):
200 self
.path_menu(self
.template_paths
, "text.open", props_default
={"internal": True})
203 def menu_func_templates(self
, context
):
204 """Add POV files to the text editor templates menu"""
205 # Do not depend on POV being active renderer here...
206 self
.layout
.menu("TEXT_MT_POV_templates")
209 # ---------------------------------------------------------------- #
213 class VIEW_MT_POV_import(Menu
):
214 """Use this class for the import menu."""
216 bl_idname
= "POVRAY_MT_import_tools"
219 def draw(self
, context
):
221 layout
.operator_context
= 'INVOKE_REGION_WIN'
222 layout
.operator("import_scene.pov", icon
="FORCE_LENNARDJONES")
225 def menu_func_import(self
, context
):
226 """Add the import operator to menu"""
227 engine
= context
.scene
.render
.engine
228 if engine
== 'POVRAY_RENDER':
229 self
.layout
.operator("import_scene.pov", icon
="FORCE_LENNARDJONES")
236 TEXT_PT_POV_custom_code
,
237 TEXT_MT_POV_templates
,
245 bpy
.types
.TOPBAR_MT_file_import
.append(menu_func_import
)
246 bpy
.types
.TEXT_MT_templates
.append(menu_func_templates
)
250 bpy
.types
.TEXT_MT_templates
.remove(menu_func_templates
)
251 bpy
.types
.TOPBAR_MT_file_import
.remove(menu_func_import
)
253 for cls
in reversed(classes
):
254 unregister_class(cls
)