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 """
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
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
):
26 # Implicit else, as here return was still not triggered:
28 "User Preferences path to povray documents %r NOT FOUND, checking $PATH" % pov_documents
32 if platform
.startswith("win"):
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
):
43 except FileNotFoundError
:
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
):
57 # ---------------------------------------------------------------- #
60 class TextButtonsPanel
:
61 """Use this class to define buttons from the side tab of
64 bl_space_type
= "TEXT_EDITOR"
67 COMPAT_ENGINES
= {"POVRAY_RENDER"}
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"
87 filepath
: bpy
.props
.StringProperty(name
="Filepath", subtype
="FILE_PATH")
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())
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 ."""
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
)
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."""
141 COMPAT_ENGINES
= {"POVRAY_RENDER"}
143 def draw(self
, context
):
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
)
153 layout
.label(text
="Please configure ", icon
="INFO")
154 layout
.label(text
="default pov include path ")
155 layout
.label(text
="in addon preferences")
158 "preferences.addon_show",
159 text
="Go to Render: Persistence of Vision addon",
161 ).module
= "render_povray"
165 box
.label(text
="Source to render:", icon
="RENDER_STILL")
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."""
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 # ---------------------------------------------------------------- #
209 class VIEW_MT_POV_import(Menu
):
210 """Use this class for the import menu."""
212 bl_idname
= "POVRAY_MT_import_tools"
215 def draw(self
, context
):
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")
232 TEXT_PT_POV_custom_code
,
233 TEXT_MT_POV_templates
,
241 bpy
.types
.TOPBAR_MT_file_import
.append(menu_func_import
)
242 bpy
.types
.TEXT_MT_templates
.append(menu_func_templates
)
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
)