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 """
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
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
):
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 if pov_documents
:= locate_docpath():
151 # print(pov_documents)
152 layout
.menu(TEXT_MT_POV_insert
.bl_idname
)
155 layout
.label(text
="Please configure ", icon
="INFO")
156 layout
.label(text
="default pov include path ")
157 layout
.label(text
="in addon preferences")
160 "preferences.addon_show",
161 text
="Go to Render: Persistence of Vision addon",
163 ).module
= "render_povray"
167 box
.label(text
="Source to render:", icon
="RENDER_STILL")
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."""
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 # ---------------------------------------------------------------- #
211 class VIEW_MT_POV_import(Menu
):
212 """Use this class for the import menu."""
214 bl_idname
= "POVRAY_MT_import_tools"
217 def draw(self
, context
):
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")
234 TEXT_PT_POV_custom_code
,
235 TEXT_MT_POV_templates
,
243 bpy
.types
.TOPBAR_MT_file_import
.append(menu_func_import
)
244 bpy
.types
.TEXT_MT_templates
.append(menu_func_templates
)
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
)