Sun Position: update HDRI mode shader for Metal compatibility
[blender-addons.git] / render_povray / scripting_gui.py
blob9c3104d2ab55ec2f7e3035a0d0f7e38fcc3240c2
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 """User interface to POV Scene Description Language snippets or full includes:
5 import, load, create or edit """
7 import bpy
8 from bpy.utils import register_class, unregister_class
9 from bpy.types import Operator, Menu, Panel
10 from sys import platform # really import here, as in ui.py and in render.py?
11 import os # really import here and in render.py?
12 from os.path import isfile
15 def locate_docpath():
16 """POV can be installed with some include files.
18 Get their path as defined in user preferences or registry keys for
19 the user to be able to invoke them."""
21 addon_prefs = bpy.context.preferences.addons[__package__].preferences
22 # Use the system preference if its set.
23 if pov_documents := addon_prefs.docpath_povray:
24 if os.path.exists(pov_documents):
25 return pov_documents
26 # Implicit else, as here return was still not triggered:
27 print(
28 "User Preferences path to povray documents %r NOT FOUND, checking $PATH" % pov_documents
31 # Windows Only
32 if platform.startswith("win"):
33 import winreg
35 try:
36 win_reg_key = winreg.OpenKey(
37 winreg.HKEY_CURRENT_USER, "Software\\POV-Ray\\v3.7\\Windows"
39 win_docpath = winreg.QueryValueEx(win_reg_key, "DocPath")[0]
40 pov_documents = os.path.join(win_docpath, "Insert Menu")
41 if os.path.exists(pov_documents):
42 return pov_documents
43 except FileNotFoundError:
44 return ""
45 # search the path all os's
46 pov_documents_default = "include"
48 os_path_ls = os.getenv("PATH").split(":") + [""]
50 for dir_name in os_path_ls:
51 pov_documents = os.path.join(dir_name, pov_documents_default)
52 if os.path.exists(pov_documents):
53 return pov_documents
54 return ""
57 # ---------------------------------------------------------------- #
60 class TextButtonsPanel:
61 """Use this class to define buttons from the side tab of
62 text window."""
64 bl_space_type = "TEXT_EDITOR"
65 bl_region_type = "UI"
66 bl_label = "POV-Ray"
67 COMPAT_ENGINES = {"POVRAY_RENDER"}
69 @classmethod
70 def poll(cls, context):
71 text = context.space_data
72 rd = context.scene.render
73 return text and (rd.engine in cls.COMPAT_ENGINES)
76 # ---------------------------------------------------------------- #
77 # Text Povray Settings
78 # ---------------------------------------------------------------- #
81 class TEXT_OT_POV_insert(Operator):
82 """Create blender text editor operator to insert pov snippets like other pov IDEs"""
84 bl_idname = "text.povray_insert"
85 bl_label = "Insert"
87 filepath: bpy.props.StringProperty(name="Filepath", subtype="FILE_PATH")
89 @classmethod
90 def poll(cls, context):
91 text = context.space_data.text
92 return context.area.type == "TEXT_EDITOR" and text is not None
93 # return bpy.ops.text.insert.poll() this Bpy op has no poll()
95 def execute(self, context):
96 if self.filepath and isfile(self.filepath):
97 with open(self.filepath, "r") as file:
98 bpy.ops.text.insert(text=file.read())
100 # places the cursor at the end without scrolling -.-
101 # context.space_data.text.write(file.read())
102 if not file.closed:
103 file.close()
104 return {"FINISHED"}
107 def validinsert(ext):
108 """Since preview images could be in same folder, filter only insertable text"""
109 return ext in {".txt", ".inc", ".pov"}
112 class TEXT_MT_POV_insert(Menu):
113 """Create a menu launcher in text editor for the TEXT_OT_POV_insert operator ."""
115 bl_label = "Insert"
116 bl_idname = "TEXT_MT_POV_insert"
118 def draw(self, context):
119 pov_documents = locate_docpath()
120 prop = self.layout.operator("wm.path_open", text="Open folder", icon="FILE_FOLDER")
121 prop.filepath = pov_documents
122 self.layout.separator()
124 # todo: structure submenus by dir
125 pov_insert_items_list = [root for root, dirs, files in os.walk(pov_documents)]
126 print(pov_insert_items_list)
127 self.path_menu(
128 pov_insert_items_list,
129 "text.povray_insert",
130 # {"internal": True},
131 filter_ext=validinsert,
135 class TEXT_PT_POV_custom_code(TextButtonsPanel, Panel):
136 """Use this class to create a panel in text editor for the user to decide if he renders text
138 only or adds to 3d scene."""
140 bl_label = "POV"
141 COMPAT_ENGINES = {"POVRAY_RENDER"}
143 def draw(self, context):
144 layout = self.layout
146 text = context.space_data.text
148 if pov_documents := locate_docpath():
149 # print(pov_documents)
150 layout.menu(TEXT_MT_POV_insert.bl_idname)
152 else:
153 layout.label(text="Please configure ", icon="INFO")
154 layout.label(text="default pov include path ")
155 layout.label(text="in addon preferences")
156 # layout.separator()
157 layout.operator(
158 "preferences.addon_show",
159 text="Go to Render: Persistence of Vision addon",
160 icon="PREFERENCES",
161 ).module = "render_povray"
163 if text:
164 box = layout.box()
165 box.label(text="Source to render:", icon="RENDER_STILL")
166 row = box.row()
167 row.prop(text.pov, "custom_code", expand=True)
168 if text.pov.custom_code in {"3dview"}:
169 box.operator("render.render", icon="OUTLINER_DATA_ARMATURE")
170 if text.pov.custom_code in {"text"}:
171 rtext = bpy.context.space_data.text # is r a typo ? or why written, not used
172 box.operator("text.run", icon="ARMATURE_DATA")
173 # layout.prop(text.pov, "custom_code")
174 elif text.pov.custom_code in {"both"}:
175 box.operator("render.render", icon="POSE_HLT")
176 layout.label(text="Please specify declared", icon="INFO")
177 layout.label(text="items in properties ")
178 # layout.label(text="")
179 layout.label(text="replacement fields")
182 # ---------------------------------------------------------------- #
183 # Text editor templates from header menu
186 class TEXT_MT_POV_templates(Menu):
187 """Use this class to create a menu for the same pov templates scenes as other pov IDEs."""
189 bl_label = "POV"
191 # We list templates on file evaluation, we can assume they are static data,
192 # and better avoid running this on every draw call.
193 template_paths = [os.path.join(os.path.dirname(__file__), "templates_pov")]
195 def draw(self, context):
196 self.path_menu(self.template_paths, "text.open", props_default={"internal": True})
199 def menu_func_templates(self, context):
200 """Add POV files to the text editor templates menu"""
201 # Do not depend on POV being active renderer here...
202 self.layout.menu("TEXT_MT_POV_templates")
205 # ---------------------------------------------------------------- #
206 # POV Import menu
209 class VIEW_MT_POV_import(Menu):
210 """Use this class for the import menu."""
212 bl_idname = "POVRAY_MT_import_tools"
213 bl_label = "Import"
215 def draw(self, context):
216 layout = self.layout
217 layout.operator_context = "INVOKE_REGION_WIN"
218 layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
221 def menu_func_import(self, context):
222 """Add the import operator to menu"""
223 engine = context.scene.render.engine
224 if engine == "POVRAY_RENDER":
225 self.layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
228 classes = (
229 VIEW_MT_POV_import,
230 TEXT_OT_POV_insert,
231 TEXT_MT_POV_insert,
232 TEXT_PT_POV_custom_code,
233 TEXT_MT_POV_templates,
237 def register():
238 for cls in classes:
239 register_class(cls)
241 bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
242 bpy.types.TEXT_MT_templates.append(menu_func_templates)
245 def unregister():
246 bpy.types.TEXT_MT_templates.remove(menu_func_templates)
247 bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
249 for cls in reversed(classes):
250 unregister_class(cls)