diff --git a/build/make_blender_plugin.nxt b/build/make_blender_plugin.nxt deleted file mode 100644 index 65d624a..0000000 --- a/build/make_blender_plugin.nxt +++ /dev/null @@ -1,45 +0,0 @@ -{ - "version": "1.17", - "alias": "make_blender_plugin", - "color": "#e87d0d", - "mute": false, - "solo": false, - "meta_data": { - "positions": { - "/make_addon": [ - 0.0, - 0.0 - ] - }, - "collapse": { - "/make_addon": false - } - }, - "nodes": { - "/": { - "attrs": { - "addon_folder": { - "type": "raw", - "value": "${path::nxt_blender}" - }, - "intergation_folder": { - "type": "raw", - "value": "${file::../nxt_editor/integration/blender}" - } - }, - "code": [ - "import os", - "import shutil" - ] - }, - "/make_addon": { - "start_point": true, - "code": [ - "if os.path.isdir('${addon_folder}'):", - " shutil.rmtree('${addon_folder}')", - " print('removed old blender build')", - "shutil.copytree('${intergation_folder}', '${addon_folder}')" - ] - } - } -} \ No newline at end of file diff --git a/build/release_footer.md b/build/release_footer.md index 825cf84..3b593c4 100644 --- a/build/release_footer.md +++ b/build/release_footer.md @@ -8,15 +8,14 @@ Each described installation is self contained, and produces a working nxt. ## Pip Installation From a Python 3 environment run the following command: `pip install nxt-editor` -**Python Dependancies** +**Python Dependencies** - [nxt-core](https://github.com/nxt-dev/nxt) - [Qt.py](https://github.com/mottosso/Qt.py) - [PySide6](https://doc.qt.io/qtforpython-6/gettingstarted.html) ## Blender (2.8 and newer) Installation -1. Download Blender addon (nxt_blender.zip) -2. Extract and follow `README.md` inside +See the [latest release of nxt-blender](https://github.com/nxt-dev/nxt-blender/releases/latest). ### Blender update - Automatically: NXT > Update NXT diff --git a/nxt_editor/integration/blender/README.md b/nxt_editor/integration/blender/README.md index b59c230..cd30cd1 100644 --- a/nxt_editor/integration/blender/README.md +++ b/nxt_editor/integration/blender/README.md @@ -1,67 +1,2 @@ -# Installation -**This is an experimental version of nxt_blender. Save early, save often.** -This is a Blender addon for nxt. Note that it will access the internet to install. -Please read all the steps below before starting. - -_In some of our testing we found that we needed to install Python on -the system inorder for Blender to be able to open the NXT editor. If you -get strange import errors when you try to import `nxt_editor`, try -installing Python (same version as Blender's) on your machine._ - -### By hand (if you're familiar with pip) -1. Locate the path to blenders Python interpreter - - In Blender, you can run `sys.exec_prefix` to find the folder containing the Python executable -2. Open Terminal, CMD, ect. - Must have elevated permissions -3. Run: `/path/to/blender/python.exe -m pip install nxt-editor` -4. Start Blender -5. Open the addon manager (Edit > Preferences > Add-ons) -6. Click "Install" and select the `nxt_blender.py` file provided with this addon zip -7. To launch NXT navigate the newly created `NXT` menu and select `Open Editor` - - -### Automated -1. Launch Blender with elevated permissions -2. Open the addon manager (Edit > Preferences > Add-ons) -3. Click "Install" and select the `nxt_blender.py` file provided with this addon zip - * In newer versions of Blender you need to click the small arrow on the top right and select "Install from Disk". -4. Enable the `NXT Blender` and twirl down the addon preferences -5. Click `Install NXT dependencies` - - It is recommended to open the console window before running the script, so you can see what's happening. Window > Toggle System Console. - - The installation may take a minute or two, during this time Blender will be unresponsive. -6. Restart Blender - -# Usage -- Ensure the `NXT Blender` addon is enabled -- To launch NXT navigate the newly created `NXT` menu and select `Open Editor` - -# Updating -_These steps also require elevated permissions for Blender or the terminal._ -### By hand (if you're familiar with pip) -1. In terminal or cmd run: `/path/to/blender/python.exe -m pip install -U nxt-editor nxt` -2. Restart Blender - -### Automated -1. Open the addon manager (Edit > Preferences > Add-ons) -3. Locate the `NXT Blender` and twirl down the addon preferences -3. Click `Update NXT dependencies` -4. Restart Blender - -_or_ - -1. Navigate to the NXT menu -2. Click `Update NXT` -3. Restart Blender - -# Uninstall -_These steps also require elevated permissions for Blender or the terminal._ -### By hand (if you're familiar with pip) -1. Open the addon manager (Edit > Preferences > Add-ons) -2. Locate the `NXT Blender` and twirl down the addon preferences -3. Click 'Remove' -1. In terminal or cmd run: `/path/to/blender/python.exe -m pip uninstall nxt-editor nxt -y` - -### Automated -1. Open the addon manager (Edit > Preferences > Add-ons) -3. Locate the `NXT Blender` and twirl down the addon preferences -3. Click `Uninstall NXT dependencies` -3. When that finishes, click the 'Remove' button \ No newline at end of file +# NXT Blender +If you're interesting in using the NXT visual editor, directly in Blender, checkout our [nxt-blender](https://github.com/nxt-dev/nxt-blender) project! \ No newline at end of file diff --git a/nxt_editor/integration/blender/__init__.py b/nxt_editor/integration/blender/__init__.py deleted file mode 100644 index 9776fe8..0000000 --- a/nxt_editor/integration/blender/__init__.py +++ /dev/null @@ -1,190 +0,0 @@ -# Builtin -import atexit -import os -import shutil -import subprocess -import sys - -# External -import bpy -from Qt import QtCore, QtWidgets - -# Internal -from nxt.constants import NXT_DCC_ENV_VAR -from nxt_editor.integration import NxtIntegration -import nxt_editor - -__NXT_INTEGRATION__ = None -b_major, b_minor, b_patch = bpy.app.version - - -class Blender(NxtIntegration): - def __init__(self): - super(Blender, self).__init__(name='blender') - b_major, b_minor, b_patch = bpy.app.version - if b_major == 2 and b_minor < 80: - raise RuntimeError('Blender version is not compatible with this ' - 'version of nxt.') - if b_major == 2: - addons_dir = bpy.utils.user_resource('SCRIPTS', 'addons') - else: - addons_dir = os.path.join(bpy.utils.user_resource('SCRIPTS'), - '/addons') - self.addons_dir = addons_dir.replace(os.sep, '/') - self.instance = None - self.nxt_qapp = QtWidgets.QApplication.instance() - - @staticmethod - def show_message(message, title, icon='INFO'): - - def draw(self, *args): - self.layout.label(text=message) - - bpy.context.window_manager.popup_menu(draw, title=title, icon=icon) - - @classmethod - def setup(cls): - self = cls() - bpy.ops.preferences.addon_disable(module='nxt_' + self.name) - integration_filepath = self.get_integration_filepath() - shutil.copy(integration_filepath, self.addons_dir) - bpy.ops.preferences.addon_enable(module='nxt_' + self.name) - - def _install_and_import_package(self, module_name, package_name=None, - global_name=None): - """Calls a subprocess to pip install the given package name and then - attempts to import the new package. - - :param module_name: Desired module to import after install - :param package_name: pip package name - :param global_name: Global name to access the module if different - than the module name. - :raises: subprocess.CalledProcessError - :return: bool - """ - if package_name is None: - package_name = module_name - if global_name is None: - global_name = module_name - environ_copy = dict(os.environ) - environ_copy["PYTHONNOUSERSITE"] = "1" - pkg = 'nxt-editor' - if b_major == 2: - exe = bpy.app.binary_path_python - else: - exe = sys.executable - print('INSTLALING: ' + pkg) - subprocess.run([exe, "-m", "pip", "install", pkg], - check=True, env=environ_copy) - success = self._safe_import_package(package_name=package_name, - global_name=global_name) - Blender.show_message('NXT package Installed! ' - 'You may need to restart Blender.', - 'Success!') - return success - - @staticmethod - def _update_package(package_name): - """Calls a subprocess to pip update the given package name. - - :param package_name: pip package name - :raises: subprocess.CalledProcessError - :return: None - """ - environ_copy = dict(os.environ) - environ_copy["PYTHONNOUSERSITE"] = "1" - if b_major == 2: - exe = bpy.app.binary_path_python - else: - exe = sys.executable - subprocess.run([exe, "-m", "pip", "install", "-U", - package_name], check=True, env=environ_copy) - Blender.show_message('NXT package updated! ' - 'Please restart Blender.', 'Success!') - - @classmethod - def update(cls): - self = cls() - og_cwd = os.getcwd() - super(Blender, self).update() - os.chdir(og_cwd) - addon_file = os.path.join(os.path.dirname(__file__), 'nxt_blender.py') - shutil.copy(addon_file, self.addons_dir) - - @classmethod - def launch_nxt(cls): - global __NXT_INTEGRATION__ - if __NXT_INTEGRATION__: - self = __NXT_INTEGRATION__ - else: - self = cls() - __NXT_INTEGRATION__ = self - os.environ[NXT_DCC_ENV_VAR] = 'blender' - if self.instance: - self.instance.show() - return - if not self.nxt_qapp: - self.nxt_qapp = nxt_editor._new_qapp() - nxt_win = nxt_editor.show_new_editor(start_rpc=False) - else: - nxt_win = nxt_editor.show_new_editor(start_rpc=False) - if 'win32' in sys.platform: - # gives nxt it's own entry on taskbar - nxt_win.setWindowFlags(QtCore.Qt.Window) - - def unregister_nxt(): - self.instance = None - - nxt_win.close_signal.connect(unregister_nxt) - nxt_win.show() - # Forces keyboard focus - nxt_win.activateWindow() - atexit.register(nxt_win.close) - self.instance = nxt_win - return self - - def quit_nxt(self): - if self.instance: - atexit.unregister(self.instance.close) - self.instance.close() - if self.nxt_qapp: - self.nxt_qapp.quit() - global __NXT_INTEGRATION__ - __NXT_INTEGRATION__ = None - - def create_context(self): - placeholder_txt = 'Blender {}.{}'.format(*bpy.app.version) - args = ['-noaudio', '--background', '--python'] - self.instance.create_remote_context(placeholder_txt, - interpreter_exe=bpy.app.binary_path, - exe_script_args=args) - - def check_for_nxt_core(self, install=False): - success = super(Blender, self).check_for_nxt_core(install=install) - if not success: - Blender.show_message('Failed to import and/or install ' - 'nxt-editor.', 'Failed!') - return success - - @staticmethod - def _uninstall_package(package_name): - """Calls a subprocess to pip uninstall the given package name. Will - NOT prompt the user to confrim uninstall. - - :param package_name: pip package name - :raises: subprocess.CalledProcessError - :return: None - """ - environ_copy = dict(os.environ) - environ_copy["PYTHONNOUSERSITE"] = "1" - if b_major == 2: - exe = bpy.app.binary_path_python - else: - exe = sys.executable - subprocess.run([exe, "-m", "pip", "uninstall", - package_name, '-y'], check=True, env=environ_copy) - - def uninstall(self): - super(Blender, self).uninstall() - Blender.show_message('NXT was uninstalled, sorry ' - 'to see you go.', 'Uninstalled!') diff --git a/nxt_editor/integration/blender/nxt_blender.py b/nxt_editor/integration/blender/nxt_blender.py deleted file mode 100644 index c3729cc..0000000 --- a/nxt_editor/integration/blender/nxt_blender.py +++ /dev/null @@ -1,274 +0,0 @@ -""" -Loosely based on the example addon from this repo: -https://github.com/robertguetzkow/blender-python-examples -""" -# Builtin -import os -import sys -import subprocess - -# External -import bpy - -try: - # External - from Qt import QtCore, QtWidgets - # Internal - from nxt_editor.constants import NXT_WEBSITE - from nxt_editor.integration import blender - nxt_installed = True -except ImportError: - nxt_installed = False - NXT_WEBSITE = 'https://nxt-dev.github.io/' - -nxt_package_name = 'nxt-editor' - -bl_info = { - "name": "NXT Blender", - "blender": (3, 4, 0), - "version": (0, 4, 0), - "location": "NXT > Open Editor", - "wiki_url": "https://nxt-dev.github.io/", - "tracker_url": "https://github.com/nxt-dev/nxt_editor/issues", - "category": "nxt", - "description": "NXT is a general purpose code compositor designed for " - "rigging, scene assembly, and automation. (This is an " - "experimental version of nxt_blender. Save " - "early, save often.)", - "warning": "This addon requires installation of dependencies." -} - -b_major, b_minor, b_patch = bpy.app.version -if b_major == 2: - bl_info["blender"] = (2, 80, 0) -elif b_major > 4: - raise RuntimeError('NXT does not support Blender version: ' - '{}.x'.format(b_major)) - - -class BLENDER_PLUGIN_VERSION(object): - plugin_v_data = {'MAJOR': bl_info["version"][0], - 'MINOR': bl_info["version"][1], - 'PATCH': bl_info["version"][2]} - MAJOR = plugin_v_data['MAJOR'] - MINOR = plugin_v_data['MINOR'] - PATCH = plugin_v_data['PATCH'] - VERSION_TUPLE = (MAJOR, MINOR, PATCH) - VERSION_STR = '.'.join(str(v) for v in VERSION_TUPLE) - VERSION = VERSION_STR - - -class CreateBlenderContext(bpy.types.Operator): - bl_label = "Create Remote Blender NXT Context" - bl_idname = "nxt.create_blender_context" - - def execute(self, context): - global nxt_installed - if nxt_installed: - b = blender.__NXT_INTEGRATION__ - if not b: - b = blender.Blender.launch_nxt() - b.create_context() - else: - show_dependency_warning() - return {'FINISHED'} - - -class OpenNxtEditor(bpy.types.Operator): - bl_label = "Open NXT Editor" - bl_idname = "nxt.nxt_editor" - - def execute(self, context): - global nxt_installed - if nxt_installed: - blender.Blender.launch_nxt() - else: - show_dependency_warning() - return {'FINISHED'} - - -class AboutNxt(bpy.types.Operator): - bl_label = "Update NXT" - bl_idname = "nxt.nxt_about" - - def execute(self, context): - import webbrowser - webbrowser.open_new(NXT_WEBSITE) - return {'FINISHED'} - - -class TOPBAR_MT_nxt(bpy.types.Menu): - bl_label = "NXT" - - def draw(self, context): - layout = self.layout - layout.operator("nxt.nxt_editor", text="Open Editor") - layout.separator() - layout.operator("nxt.nxt_update_dependencies", - text="Update NXT (Requires Blender Restart)") - layout.separator() - layout.operator('nxt.create_blender_context', text='Create Blender ' - 'Context') - layout.separator() - layout.operator("nxt.nxt_about", text="About") - - def menu_draw(self, context): - self.layout.menu("TOPBAR_MT_nxt") - - -class NxtInstallDependencies(bpy.types.Operator): - bl_idname = 'nxt.nxt_install_dependencies' - bl_label = "Install NXT dependencies (Blender requires elevated permissions)" - bl_description = ("Downloads and installs the required python packages " - "for NXT. Internet connection is required. " - "Blender may have to be started with elevated " - "permissions in order to install the package. " - "Alternatively you can pip install nxt-editor into your " - "Blender Python environment.") - bl_options = {"REGISTER", "INTERNAL"} - - @classmethod - def poll(cls, context): - global nxt_installed - return not nxt_installed - - def execute(self, context): - environ_copy = dict(os.environ) - environ_copy["PYTHONNOUSERSITE"] = "1" - pkg = 'nxt-editor' - if b_major == 2: - exe = bpy.app.binary_path_python - else: - exe = sys.executable - try: - subprocess.run([exe, "-m", "pip", "install", pkg], - check=True, env=environ_copy) - except subprocess.CalledProcessError as e: - self.report({"ERROR"}, str(e)) - return {"CANCELLED"} - msg = 'Please restart Blender to finish installing NXT.' - self.report({"INFO"}, msg) - show_message(msg, "Installed dependencies!") - return {"FINISHED"} - - -class NxtUpdateDependencies(bpy.types.Operator): - bl_idname = 'nxt.nxt_update_dependencies' - bl_label = "Update NXT dependencies" - bl_description = ("Downloads and updates the required python packages " - "for NXT. Internet connection is required. " - "Blender may have to be started with elevated " - "permissions in order to install the package. " - "Alternatively you can pip install -U nxt-editor into " - "your Blender Python environment.") - bl_options = {"REGISTER", "INTERNAL"} - - @classmethod - def poll(cls, context): - global nxt_installed - return nxt_installed - - def execute(self, context): - try: - blender.Blender._update_package('nxt-editor') - except subprocess.CalledProcessError as e: - self.report({"ERROR"}, str(e)) - return {"CANCELLED"} - self.report({"INFO"}, 'Please restart Blender to ' - 'finish updating NXT.') - return {"FINISHED"} - - -class NxtUninstallDependencies(bpy.types.Operator): - bl_idname = 'nxt.nxt_uninstall_dependencies' - bl_label = "Uninstall NXT dependencies" - bl_description = ("Uninstalls the NXT Python packages. " - "Blender may have to be started with elevated " - "permissions in order to install the package. " - "Alternatively you can pip uninstall nxt-editor from " - "your Blender Python environment.") - bl_options = {"REGISTER", "INTERNAL"} - - @classmethod - def poll(cls, context): - global nxt_installed - return nxt_installed - - def execute(self, context): - try: - blender.Blender().uninstall() - except subprocess.CalledProcessError as e: - self.report({"ERROR"}, str(e)) - return {"CANCELLED"} - self.report({"INFO"}, 'Please restart Blender to ' - 'finish uninstalling NXT dependencies.') - return {"FINISHED"} - - -class NxtDependenciesPreferences(bpy.types.AddonPreferences): - bl_idname = __name__ - - def draw(self, context): - layout = self.layout - layout.operator(NxtInstallDependencies.bl_idname, icon="PLUGIN") - layout.operator(NxtUpdateDependencies.bl_idname, icon="SCRIPT") - layout.operator(NxtUninstallDependencies.bl_idname, icon="PANEL_CLOSE") - - -def show_dependency_warning(): - - def draw(self, context): - layout = self.layout - lines = [ - f"Please install the missing dependencies for the NXT add-on.", - "1. Open the preferences (Edit > Preferences > Add-ons).", - f"2. Search for the \"{bl_info.get('name')}\" add-on.", - "3. Open the details section of the add-on.", - f"4. Click on the \"{NxtInstallDependencies.bl_label}\" button.", - "This will download and install the missing Python packages. " - "You man need to start Blender with elevated permissions", - f"Alternatively you can pip install \"{nxt_package_name}\" into " - f"your Blender Python environment." - ] - - for line in lines: - layout.label(text=line) - bpy.context.window_manager.popup_menu(draw, title='NXT Warning!', - icon="ERROR") - - -def show_message(message, title, icon='INFO'): - - def draw(self, *args): - self.layout.label(text=message) - - bpy.context.window_manager.popup_menu(draw, title=title, icon=icon) - - -nxt_operators = (TOPBAR_MT_nxt, OpenNxtEditor, NxtUpdateDependencies, - NxtUninstallDependencies, NxtDependenciesPreferences, - NxtInstallDependencies, CreateBlenderContext) - - -def register(): - global nxt_installed - for cls in nxt_operators: - bpy.utils.register_class(cls) - bpy.utils.register_class(AboutNxt) - bpy.types.TOPBAR_MT_editor_menus.append(TOPBAR_MT_nxt.menu_draw) - - -def unregister(): - try: - if blender.__NXT_INTEGRATION__: - blender.__NXT_INTEGRATION__.quit_nxt() - except NameError: - pass - bpy.types.TOPBAR_MT_editor_menus.remove(TOPBAR_MT_nxt.menu_draw) - for cls in nxt_operators: - bpy.utils.unregister_class(cls) - bpy.utils.unregister_class(AboutNxt) - - -if __name__ == "__main__": - register() diff --git a/setup.py b/setup.py index 6574614..5191f1b 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ ed_patch = ed_v_data['PATCH'] editor_version = '{}.{}.{}'.format(ed_major, ed_minor, ed_patch) setuptools.setup( - name="nxt-editor", + name="nxt_editor", version=editor_version, author="The nxt contributors", author_email="dev@opennxt.dev",