Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions openpype/hosts/fusion/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import os

HOST_DIR = os.path.dirname(
os.path.abspath(__file__)
)
68 changes: 49 additions & 19 deletions openpype/hosts/fusion/api/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,16 @@

from Qt import QtWidgets, QtCore

from avalon import api
from openpype.tools.utils import host_tools

from openpype.style import load_stylesheet
from openpype.hosts.fusion.scripts import (
set_rendermode,
duplicate_with_inputs
)


def load_stylesheet():
path = os.path.join(os.path.dirname(__file__), "menu_style.qss")
if not os.path.exists(path):
print("Unable to load stylesheet, file not found in resources")
return ""

with open(path, "r") as file_stream:
stylesheet = file_stream.read()
return stylesheet


class Spacer(QtWidgets.QWidget):
def __init__(self, height, *args, **kwargs):
super(Spacer, self).__init__(*args, **kwargs)
Expand Down Expand Up @@ -54,13 +45,22 @@ def __init__(self, *args, **kwargs):
)
self.render_mode_widget = None
self.setWindowTitle("OpenPype")
workfiles_btn = QtWidgets.QPushButton("Workfiles ...", self)
create_btn = QtWidgets.QPushButton("Create ...", self)
publish_btn = QtWidgets.QPushButton("Publish ...", self)
load_btn = QtWidgets.QPushButton("Load ...", self)
inventory_btn = QtWidgets.QPushButton("Inventory ...", self)
libload_btn = QtWidgets.QPushButton("Library ...", self)
rendermode_btn = QtWidgets.QPushButton("Set render mode ...", self)

asset_label = QtWidgets.QLabel("Context", self)
asset_label.setStyleSheet("""QLabel {
font-size: 14px;
font-weight: 600;
color: #5f9fb8;
}""")
asset_label.setAlignment(QtCore.Qt.AlignHCenter)

workfiles_btn = QtWidgets.QPushButton("Work Files", self)
create_btn = QtWidgets.QPushButton("Create...", self)
load_btn = QtWidgets.QPushButton("Load...", self)
publish_btn = QtWidgets.QPushButton("Publish...", self)
inventory_btn = QtWidgets.QPushButton("Manage...", self)
libload_btn = QtWidgets.QPushButton("Library...", self)
rendermode_btn = QtWidgets.QPushButton("Set render mode...", self)
duplicate_with_inputs_btn = QtWidgets.QPushButton(
"Duplicate with input connections", self
)
Expand All @@ -71,10 +71,17 @@ def __init__(self, *args, **kwargs):
layout = QtWidgets.QVBoxLayout(self)
layout.setContentsMargins(10, 20, 10, 20)

layout.addWidget(asset_label)

layout.addWidget(Spacer(15, self))

layout.addWidget(workfiles_btn)

layout.addWidget(Spacer(15, self))

layout.addWidget(create_btn)
layout.addWidget(publish_btn)
layout.addWidget(load_btn)
layout.addWidget(publish_btn)
layout.addWidget(inventory_btn)

layout.addWidget(Spacer(15, self))
Expand All @@ -92,6 +99,9 @@ def __init__(self, *args, **kwargs):

self.setLayout(layout)

# Store reference so we can update the label
self.asset_label = asset_label

workfiles_btn.clicked.connect(self.on_workfile_clicked)
create_btn.clicked.connect(self.on_create_clicked)
publish_btn.clicked.connect(self.on_publish_clicked)
Expand All @@ -103,6 +113,26 @@ def __init__(self, *args, **kwargs):
self.on_duplicate_with_inputs_clicked)
reset_resolution_btn.clicked.connect(self.on_reset_resolution_clicked)

self._callbacks = []
self.register_callback("taskChanged", self.on_task_changed)
self.on_task_changed()

def on_task_changed(self):
# Update current context label
label = api.Session["AVALON_ASSET"]
self.asset_label.setText(label)

def register_callback(self, name, fn):

# Create a wrapper callback that we only store
# for as long as we want it to persist as callback
callback = lambda *args: fn()
self._callbacks.append(callback)
api.on(name, callback)

def deregister_all_callbacks(self):
self._callbacks[:] = []

def on_workfile_clicked(self):
print("Clicked Workfile")
host_tools.show_workfiles()
Expand Down
29 changes: 0 additions & 29 deletions openpype/hosts/fusion/api/menu_style.qss

This file was deleted.

10 changes: 2 additions & 8 deletions openpype/hosts/fusion/api/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,6 @@ def install():
See the Maya equivalent for inspiration on how to implement this.

"""

# Disable all families except for the ones we explicitly want to see
family_states = ["imagesequence",
"camera",
"pointcache"]
avalon.data["familiesStateDefault"] = False
avalon.data["familiesStateToggled"] = family_states

log.info("openpype.hosts.fusion installed")

pyblish.register_host("fusion")
Expand All @@ -48,6 +40,8 @@ def install():
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH)

print(LOAD_PATH)

pyblish.register_callback("instanceToggled", on_pyblish_instance_toggled)


Expand Down
64 changes: 1 addition & 63 deletions openpype/hosts/fusion/api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,74 +13,12 @@
log = Logger().get_logger(__name__)


def _sync_utility_scripts(env=None):
""" Synchronizing basic utlility scripts for resolve.

To be able to run scripts from inside `Fusion/Workspace/Scripts` menu
all scripts has to be accessible from defined folder.
"""
if not env:
env = os.environ

# initiate inputs
scripts = {}
us_env = env.get("FUSION_UTILITY_SCRIPTS_SOURCE_DIR")
us_dir = env.get("FUSION_UTILITY_SCRIPTS_DIR", "")
us_paths = [os.path.join(
os.path.dirname(os.path.abspath(openpype.hosts.fusion.__file__)),
"utility_scripts"
)]

# collect script dirs
if us_env:
log.info(f"Utility Scripts Env: `{us_env}`")
us_paths = us_env.split(
os.pathsep) + us_paths

# collect scripts from dirs
for path in us_paths:
scripts.update({path: os.listdir(path)})

log.info(f"Utility Scripts Dir: `{us_paths}`")
log.info(f"Utility Scripts: `{scripts}`")

# make sure no script file is in folder
if next((s for s in os.listdir(us_dir)), None):
for s in os.listdir(us_dir):
path = os.path.normpath(
os.path.join(us_dir, s))
log.info(f"Removing `{path}`...")

# remove file or directory if not in our folders
if not os.path.isdir(path):
os.remove(path)
else:
shutil.rmtree(path)

# copy scripts into Resolve's utility scripts dir
for d, sl in scripts.items():
# directory and scripts list
for s in sl:
# script in script list
src = os.path.normpath(os.path.join(d, s))
dst = os.path.normpath(os.path.join(us_dir, s))

log.info(f"Copying `{src}` to `{dst}`...")

# copy file or directory from our folders to fusion's folder
if not os.path.isdir(src):
shutil.copy2(src, dst)
else:
shutil.copytree(src, dst)


def setup(env=None):
""" Wrapper installer started from pype.hooks.fusion.FusionPrelaunch()
"""
if not env:
env = os.environ

# synchronize resolve utility scripts
_sync_utility_scripts(env)
# todo(roy): This currently does nothing. Remove?

log.info("Fusion Pype wrapper has been installed")
60 changes: 60 additions & 0 deletions openpype/hosts/fusion/deploy/Config/openpype_menu.fu
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
Action
{
ID = "OpenPype_Menu",
Category = "OpenPype",
Name = "OpenPype Menu",

Targets =
{
Composition =
{
Execute = _Lua [=[
local scriptPath = app:MapPath("OpenPype:MenuScripts/openpype_menu.py")
if bmd.fileexists(scriptPath) == false then
print("[OpenPype Error] Can't run file: " .. scriptPath)
else
target:RunScript(scriptPath)
end
]=],
},
},
},
Action
{
ID = "OpenPype_Install_PySide2",
Category = "OpenPype",
Name = "Install PySide2",

Targets =
{
Composition =
{
Execute = _Lua [=[
local scriptPath = app:MapPath("OpenPype:MenuScripts/install_pyside2.py")
if bmd.fileexists(scriptPath) == false then
print("[OpenPype Error] Can't run file: " .. scriptPath)
else
target:RunScript(scriptPath)
end
]=],
},
},
},
Menus
{
Target = "ChildFrame",

Before "Help"
{
Sub "OpenPype"
{
"OpenPype_Menu{}",
"_",
Sub "Admin" {
"OpenPype_Install_PySide2{}"
}
}
},
},
}
6 changes: 6 additions & 0 deletions openpype/hosts/fusion/deploy/MenuScripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
### OpenPype deploy MenuScripts

Note that this `MenuScripts` is not an official Fusion folder.
OpenPype only uses this folder in `{fusion}/deploy/` to trigger the OpenPype menu actions.

They are used in the actions defined in `.fu` files in `{fusion}/deploy/Config`.
14 changes: 14 additions & 0 deletions openpype/hosts/fusion/deploy/MenuScripts/install_pyside2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This is just a quick hack for users running Py3 locally but having no
# Qt library installed
import os

try:
print("Qt library found, nothing to do.")
from Qt import QtWidgets
except ImportError as exc:
print("Assuming no Qt library is installed..")
print('Installing PySide2 for Python 3.6: '
f'{os.environ["FUSION16_PYTHON36_HOME"]}')

import subprocess
subprocess.Popen(["pip", "install", "PySide2"])
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning: This can install into e.g. OpenPype .venv due to not explicitly enough installing into the correct python.

A fix was implemented here: 3d5fd09

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@


def main(env):
# This script working directory starts in Fusion application folder.
# However the contents of that folder can conflict with Qt library dlls
# so we make sure to move out of it to avoid DLL Load Failed errors.
os.chdir("..")

from openpype.hosts.fusion.api import menu
import avalon.fusion
# Registers pype's Global pyblish plugins
Expand All @@ -20,6 +25,11 @@ def main(env):

menu.launch_openpype_menu()

# Initiate a QTimer to check if Fusion is still alive every X interval
# If Fusion is not found - kill itself
# todo(roy): Implement timer that ensures UI doesn't remain when e.g.
# Fusion closes down


if __name__ == "__main__":
result = main(os.environ)
Expand Down
19 changes: 19 additions & 0 deletions openpype/hosts/fusion/deploy/fusion_shared.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
Locked = true,
Global = {
Paths = {
Map = {
["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy",
["Reactor:"] = "$(REACTOR)",

["Config:"] = "UserPaths:Config;OpenPype:Config",
["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts;OpenPype:Scripts",
["UserPaths:"] = "UserData:;AllData:;Fusion:;Reactor:Deploy"
},
},
Script = {
PythonVersion = 3,
Python3Forced = true
},
},
}
Loading