Cleanup: trailing space
[blender-addons.git] / render_povray / scripting_gui.py
blob0ca2d94913f261c8b8646fc26aaf156bcfba917d
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # <pep8 compliant>
4 """User interface to POV Scene Description Language snippets or full includes:
6 import, load, create or edit """
8 import bpy
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
16 def locate_docpath():
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
25 if pov_documents:
26 if os.path.exists(pov_documents):
27 return pov_documents
28 # Implicit else, as here return was still not triggered:
29 print(
30 "User Preferences path to povray documents %r NOT FOUND, checking $PATH" % pov_documents
33 # Windows Only
34 if platform.startswith('win'):
35 import winreg
37 try:
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):
44 return pov_documents
45 except FileNotFoundError:
46 return ""
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):
55 return pov_documents
56 return ""
59 # ---------------------------------------------------------------- #
62 class TextButtonsPanel:
63 """Use this class to define buttons from the side tab of
64 text window."""
66 bl_space_type = 'TEXT_EDITOR'
67 bl_region_type = 'UI'
68 bl_label = "POV-Ray"
69 COMPAT_ENGINES = {'POVRAY_RENDER'}
71 @classmethod
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"
87 bl_label = "Insert"
89 filepath: bpy.props.StringProperty(name="Filepath", subtype='FILE_PATH')
91 @classmethod
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())
104 if not file.closed:
105 file.close()
106 return {'FINISHED'}
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 ."""
117 bl_label = "Insert"
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)
129 self.path_menu(
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."""
142 bl_label = "POV"
143 COMPAT_ENGINES = {'POVRAY_RENDER'}
145 def draw(self, context):
146 layout = self.layout
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")
155 # layout.separator()
156 layout.operator(
157 "preferences.addon_show",
158 text="Go to Render: Persistence of Vision addon",
159 icon="PREFERENCES",
160 ).module = "render_povray"
162 # layout.separator()
163 else:
164 # print(pov_documents)
165 layout.menu(TEXT_MT_POV_insert.bl_idname)
167 if text:
168 box = layout.box()
169 box.label(text='Source to render:', icon='RENDER_STILL')
170 row = box.row()
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."""
193 bl_label = "POV"
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 # ---------------------------------------------------------------- #
210 # POV Import menu
213 class VIEW_MT_POV_import(Menu):
214 """Use this class for the import menu."""
216 bl_idname = "POVRAY_MT_import_tools"
217 bl_label = "Import"
219 def draw(self, context):
220 layout = self.layout
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")
232 classes = (
233 VIEW_MT_POV_import,
234 TEXT_OT_POV_insert,
235 TEXT_MT_POV_insert,
236 TEXT_PT_POV_custom_code,
237 TEXT_MT_POV_templates,
241 def register():
242 for cls in classes:
243 register_class(cls)
245 bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
246 bpy.types.TEXT_MT_templates.append(menu_func_templates)
249 def unregister():
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)