Import images: add file handler
[blender-addons.git] / render_povray / scripting_gui.py
blob54f27b789bbc98161d35c13b73b9823e74760814
1 # SPDX-FileCopyrightText: 2021-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 """User interface to POV Scene Description Language snippets or full includes:
7 import, load, create or edit """
9 import bpy
10 from bpy.utils import register_class, unregister_class
11 from bpy.types import Operator, Menu, Panel
12 from sys import platform # really import here, as in ui.py and in render.py?
13 import os # really import here and in render.py?
14 from os.path import isfile
17 def locate_docpath():
18 """POV can be installed with some include files.
20 Get their path as defined in user preferences or registry keys for
21 the user to be able to invoke them."""
23 addon_prefs = bpy.context.preferences.addons[__package__].preferences
24 # Use the system preference if its set.
25 if pov_documents := addon_prefs.docpath_povray:
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 if pov_documents := locate_docpath():
151 # print(pov_documents)
152 layout.menu(TEXT_MT_POV_insert.bl_idname)
154 else:
155 layout.label(text="Please configure ", icon="INFO")
156 layout.label(text="default pov include path ")
157 layout.label(text="in addon preferences")
158 # layout.separator()
159 layout.operator(
160 "preferences.addon_show",
161 text="Go to Render: Persistence of Vision addon",
162 icon="PREFERENCES",
163 ).module = "render_povray"
165 if text:
166 box = layout.box()
167 box.label(text="Source to render:", icon="RENDER_STILL")
168 row = box.row()
169 row.prop(text.pov, "custom_code", expand=True)
170 if text.pov.custom_code in {"3dview"}:
171 box.operator("render.render", icon="OUTLINER_DATA_ARMATURE")
172 if text.pov.custom_code in {"text"}:
173 rtext = bpy.context.space_data.text # is r a typo ? or why written, not used
174 box.operator("text.run", icon="ARMATURE_DATA")
175 # layout.prop(text.pov, "custom_code")
176 elif text.pov.custom_code in {"both"}:
177 box.operator("render.render", icon="POSE_HLT")
178 layout.label(text="Please specify declared", icon="INFO")
179 layout.label(text="items in properties ")
180 # layout.label(text="")
181 layout.label(text="replacement fields")
184 # ---------------------------------------------------------------- #
185 # Text editor templates from header menu
188 class TEXT_MT_POV_templates(Menu):
189 """Use this class to create a menu for the same pov templates scenes as other pov IDEs."""
191 bl_label = "POV"
193 # We list templates on file evaluation, we can assume they are static data,
194 # and better avoid running this on every draw call.
195 template_paths = [os.path.join(os.path.dirname(__file__), "templates_pov")]
197 def draw(self, context):
198 self.path_menu(self.template_paths, "text.open", props_default={"internal": True})
201 def menu_func_templates(self, context):
202 """Add POV files to the text editor templates menu"""
203 # Do not depend on POV being active renderer here...
204 self.layout.menu("TEXT_MT_POV_templates")
207 # ---------------------------------------------------------------- #
208 # POV Import menu
211 class VIEW_MT_POV_import(Menu):
212 """Use this class for the import menu."""
214 bl_idname = "POVRAY_MT_import_tools"
215 bl_label = "Import"
217 def draw(self, context):
218 layout = self.layout
219 layout.operator_context = "INVOKE_REGION_WIN"
220 layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
223 def menu_func_import(self, context):
224 """Add the import operator to menu"""
225 engine = context.scene.render.engine
226 if engine == "POVRAY_RENDER":
227 self.layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
230 classes = (
231 VIEW_MT_POV_import,
232 TEXT_OT_POV_insert,
233 TEXT_MT_POV_insert,
234 TEXT_PT_POV_custom_code,
235 TEXT_MT_POV_templates,
239 def register():
240 for cls in classes:
241 register_class(cls)
243 bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
244 bpy.types.TEXT_MT_templates.append(menu_func_templates)
247 def unregister():
248 bpy.types.TEXT_MT_templates.remove(menu_func_templates)
249 bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
251 for cls in reversed(classes):
252 unregister_class(cls)