mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
Merge branch 'develop' into bugfix/updating_attribute_error_out_in_all_loaders_max
This commit is contained in:
commit
8eafc292e2
38 changed files with 210 additions and 881 deletions
|
|
@ -164,7 +164,7 @@ class RenderCreator(Creator):
|
||||||
api.get_stub().rename_item(comp_id,
|
api.get_stub().rename_item(comp_id,
|
||||||
new_comp_name)
|
new_comp_name)
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings["aftereffects"]["create"]["RenderCreator"]
|
project_settings["aftereffects"]["create"]["RenderCreator"]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
from openpype.hosts.fusion.api import (
|
|
||||||
comp_lock_and_undo_chunk,
|
|
||||||
get_current_comp
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
comp = get_current_comp()
|
|
||||||
"""Set all selected backgrounds to 32 bit"""
|
|
||||||
with comp_lock_and_undo_chunk(comp, 'Selected Backgrounds to 32bit'):
|
|
||||||
tools = comp.GetToolList(True, "Background").values()
|
|
||||||
for tool in tools:
|
|
||||||
tool.Depth = 5
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
from openpype.hosts.fusion.api import (
|
|
||||||
comp_lock_and_undo_chunk,
|
|
||||||
get_current_comp
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
comp = get_current_comp()
|
|
||||||
"""Set all backgrounds to 32 bit"""
|
|
||||||
with comp_lock_and_undo_chunk(comp, 'Backgrounds to 32bit'):
|
|
||||||
tools = comp.GetToolList(False, "Background").values()
|
|
||||||
for tool in tools:
|
|
||||||
tool.Depth = 5
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
from openpype.hosts.fusion.api import (
|
|
||||||
comp_lock_and_undo_chunk,
|
|
||||||
get_current_comp
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
comp = get_current_comp()
|
|
||||||
"""Set all selected loaders to 32 bit"""
|
|
||||||
with comp_lock_and_undo_chunk(comp, 'Selected Loaders to 32bit'):
|
|
||||||
tools = comp.GetToolList(True, "Loader").values()
|
|
||||||
for tool in tools:
|
|
||||||
tool.Depth = 5
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
from openpype.hosts.fusion.api import (
|
|
||||||
comp_lock_and_undo_chunk,
|
|
||||||
get_current_comp
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
comp = get_current_comp()
|
|
||||||
"""Set all loaders to 32 bit"""
|
|
||||||
with comp_lock_and_undo_chunk(comp, 'Loaders to 32bit'):
|
|
||||||
tools = comp.GetToolList(False, "Loader").values()
|
|
||||||
for tool in tools:
|
|
||||||
tool.Depth = 5
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
|
|
@ -1,200 +0,0 @@
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import glob
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from qtpy import QtWidgets, QtCore
|
|
||||||
|
|
||||||
import qtawesome as qta
|
|
||||||
|
|
||||||
from openpype.client import get_assets
|
|
||||||
from openpype import style
|
|
||||||
from openpype.pipeline import (
|
|
||||||
install_host,
|
|
||||||
get_current_project_name,
|
|
||||||
)
|
|
||||||
from openpype.hosts.fusion import api
|
|
||||||
from openpype.pipeline.context_tools import get_workdir_from_session
|
|
||||||
|
|
||||||
log = logging.getLogger("Fusion Switch Shot")
|
|
||||||
|
|
||||||
|
|
||||||
class App(QtWidgets.QWidget):
|
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
|
|
||||||
################################################
|
|
||||||
# |---------------------| |------------------| #
|
|
||||||
# |Comp | |Asset | #
|
|
||||||
# |[..][ v]| |[ v]| #
|
|
||||||
# |---------------------| |------------------| #
|
|
||||||
# | Update existing comp [ ] | #
|
|
||||||
# |------------------------------------------| #
|
|
||||||
# | Switch | #
|
|
||||||
# |------------------------------------------| #
|
|
||||||
################################################
|
|
||||||
|
|
||||||
QtWidgets.QWidget.__init__(self, parent)
|
|
||||||
|
|
||||||
layout = QtWidgets.QVBoxLayout()
|
|
||||||
|
|
||||||
# Comp related input
|
|
||||||
comp_hlayout = QtWidgets.QHBoxLayout()
|
|
||||||
comp_label = QtWidgets.QLabel("Comp file")
|
|
||||||
comp_label.setFixedWidth(50)
|
|
||||||
comp_box = QtWidgets.QComboBox()
|
|
||||||
|
|
||||||
button_icon = qta.icon("fa.folder", color="white")
|
|
||||||
open_from_dir = QtWidgets.QPushButton()
|
|
||||||
open_from_dir.setIcon(button_icon)
|
|
||||||
|
|
||||||
comp_box.setFixedHeight(25)
|
|
||||||
open_from_dir.setFixedWidth(25)
|
|
||||||
open_from_dir.setFixedHeight(25)
|
|
||||||
|
|
||||||
comp_hlayout.addWidget(comp_label)
|
|
||||||
comp_hlayout.addWidget(comp_box)
|
|
||||||
comp_hlayout.addWidget(open_from_dir)
|
|
||||||
|
|
||||||
# Asset related input
|
|
||||||
asset_hlayout = QtWidgets.QHBoxLayout()
|
|
||||||
asset_label = QtWidgets.QLabel("Shot")
|
|
||||||
asset_label.setFixedWidth(50)
|
|
||||||
|
|
||||||
asset_box = QtWidgets.QComboBox()
|
|
||||||
asset_box.setLineEdit(QtWidgets.QLineEdit())
|
|
||||||
asset_box.setFixedHeight(25)
|
|
||||||
|
|
||||||
refresh_icon = qta.icon("fa.refresh", color="white")
|
|
||||||
refresh_btn = QtWidgets.QPushButton()
|
|
||||||
refresh_btn.setIcon(refresh_icon)
|
|
||||||
|
|
||||||
asset_box.setFixedHeight(25)
|
|
||||||
refresh_btn.setFixedWidth(25)
|
|
||||||
refresh_btn.setFixedHeight(25)
|
|
||||||
|
|
||||||
asset_hlayout.addWidget(asset_label)
|
|
||||||
asset_hlayout.addWidget(asset_box)
|
|
||||||
asset_hlayout.addWidget(refresh_btn)
|
|
||||||
|
|
||||||
# Options
|
|
||||||
options = QtWidgets.QHBoxLayout()
|
|
||||||
options.setAlignment(QtCore.Qt.AlignLeft)
|
|
||||||
|
|
||||||
current_comp_check = QtWidgets.QCheckBox()
|
|
||||||
current_comp_check.setChecked(True)
|
|
||||||
current_comp_label = QtWidgets.QLabel("Use current comp")
|
|
||||||
|
|
||||||
options.addWidget(current_comp_label)
|
|
||||||
options.addWidget(current_comp_check)
|
|
||||||
|
|
||||||
accept_btn = QtWidgets.QPushButton("Switch")
|
|
||||||
|
|
||||||
layout.addLayout(options)
|
|
||||||
layout.addLayout(comp_hlayout)
|
|
||||||
layout.addLayout(asset_hlayout)
|
|
||||||
layout.addWidget(accept_btn)
|
|
||||||
|
|
||||||
self._open_from_dir = open_from_dir
|
|
||||||
self._comps = comp_box
|
|
||||||
self._assets = asset_box
|
|
||||||
self._use_current = current_comp_check
|
|
||||||
self._accept_btn = accept_btn
|
|
||||||
self._refresh_btn = refresh_btn
|
|
||||||
|
|
||||||
self.setWindowTitle("Fusion Switch Shot")
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
self.resize(260, 140)
|
|
||||||
self.setMinimumWidth(260)
|
|
||||||
self.setFixedHeight(140)
|
|
||||||
|
|
||||||
self.connections()
|
|
||||||
|
|
||||||
# Update ui to correct state
|
|
||||||
self._on_use_current_comp()
|
|
||||||
self._refresh()
|
|
||||||
|
|
||||||
def connections(self):
|
|
||||||
self._use_current.clicked.connect(self._on_use_current_comp)
|
|
||||||
self._open_from_dir.clicked.connect(self._on_open_from_dir)
|
|
||||||
self._refresh_btn.clicked.connect(self._refresh)
|
|
||||||
self._accept_btn.clicked.connect(self._on_switch)
|
|
||||||
|
|
||||||
def _on_use_current_comp(self):
|
|
||||||
state = self._use_current.isChecked()
|
|
||||||
self._open_from_dir.setEnabled(not state)
|
|
||||||
self._comps.setEnabled(not state)
|
|
||||||
|
|
||||||
def _on_open_from_dir(self):
|
|
||||||
|
|
||||||
start_dir = get_workdir_from_session()
|
|
||||||
comp_file, _ = QtWidgets.QFileDialog.getOpenFileName(
|
|
||||||
self, "Choose comp", start_dir)
|
|
||||||
|
|
||||||
if not comp_file:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Create completer
|
|
||||||
self.populate_comp_box([comp_file])
|
|
||||||
self._refresh()
|
|
||||||
|
|
||||||
def _refresh(self):
|
|
||||||
# Clear any existing items
|
|
||||||
self._assets.clear()
|
|
||||||
|
|
||||||
asset_names = self.collect_asset_names()
|
|
||||||
completer = QtWidgets.QCompleter(asset_names)
|
|
||||||
|
|
||||||
self._assets.setCompleter(completer)
|
|
||||||
self._assets.addItems(asset_names)
|
|
||||||
|
|
||||||
def _on_switch(self):
|
|
||||||
|
|
||||||
if not self._use_current.isChecked():
|
|
||||||
file_name = self._comps.itemData(self._comps.currentIndex())
|
|
||||||
else:
|
|
||||||
comp = api.get_current_comp()
|
|
||||||
file_name = comp.GetAttrs("COMPS_FileName")
|
|
||||||
|
|
||||||
asset = self._assets.currentText()
|
|
||||||
|
|
||||||
import colorbleed.scripts.fusion_switch_shot as switch_shot
|
|
||||||
switch_shot.switch(asset_name=asset, filepath=file_name, new=True)
|
|
||||||
|
|
||||||
def collect_slap_comps(self, directory):
|
|
||||||
items = glob.glob("{}/*.comp".format(directory))
|
|
||||||
return items
|
|
||||||
|
|
||||||
def collect_asset_names(self):
|
|
||||||
project_name = get_current_project_name()
|
|
||||||
asset_docs = get_assets(project_name, fields=["name"])
|
|
||||||
asset_names = {
|
|
||||||
asset_doc["name"]
|
|
||||||
for asset_doc in asset_docs
|
|
||||||
}
|
|
||||||
return list(asset_names)
|
|
||||||
|
|
||||||
def populate_comp_box(self, files):
|
|
||||||
"""Ensure we display the filename only but the path is stored as well
|
|
||||||
|
|
||||||
Args:
|
|
||||||
files (list): list of full file path [path/to/item/item.ext,]
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
|
|
||||||
for f in files:
|
|
||||||
filename = os.path.basename(f)
|
|
||||||
self._comps.addItem(filename, userData=f)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
install_host(api)
|
|
||||||
|
|
||||||
app = QtWidgets.QApplication(sys.argv)
|
|
||||||
window = App()
|
|
||||||
window.setStyleSheet(style.load_stylesheet())
|
|
||||||
window.show()
|
|
||||||
sys.exit(app.exec_())
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
"""Forces Fusion to 'retrigger' the Loader to update.
|
|
||||||
|
|
||||||
Warning:
|
|
||||||
This might change settings like 'Reverse', 'Loop', trims and other
|
|
||||||
settings of the Loader. So use this at your own risk.
|
|
||||||
|
|
||||||
"""
|
|
||||||
from openpype.hosts.fusion.api.pipeline import (
|
|
||||||
get_current_comp,
|
|
||||||
comp_lock_and_undo_chunk
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def update_loader_ranges():
|
|
||||||
comp = get_current_comp()
|
|
||||||
with comp_lock_and_undo_chunk(comp, "Reload clip time ranges"):
|
|
||||||
tools = comp.GetToolList(True, "Loader").values()
|
|
||||||
for tool in tools:
|
|
||||||
|
|
||||||
# Get tool attributes
|
|
||||||
tool_a = tool.GetAttrs()
|
|
||||||
clipTable = tool_a['TOOLST_Clip_Name']
|
|
||||||
altclipTable = tool_a['TOOLST_AltClip_Name']
|
|
||||||
startTime = tool_a['TOOLNT_Clip_Start']
|
|
||||||
old_global_in = tool.GlobalIn[comp.CurrentTime]
|
|
||||||
|
|
||||||
# Reapply
|
|
||||||
for index, _ in clipTable.items():
|
|
||||||
time = startTime[index]
|
|
||||||
tool.Clip[time] = tool.Clip[time]
|
|
||||||
|
|
||||||
for index, _ in altclipTable.items():
|
|
||||||
time = startTime[index]
|
|
||||||
tool.ProxyFilename[time] = tool.ProxyFilename[time]
|
|
||||||
|
|
||||||
tool.GlobalIn[comp.CurrentTime] = old_global_in
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
update_loader_ranges()
|
|
||||||
|
|
@ -5,7 +5,7 @@ Global = {
|
||||||
Map = {
|
Map = {
|
||||||
["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy",
|
["OpenPype:"] = "$(OPENPYPE_FUSION)/deploy",
|
||||||
["Config:"] = "UserPaths:Config;OpenPype:Config",
|
["Config:"] = "UserPaths:Config;OpenPype:Config",
|
||||||
["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts;OpenPype:Scripts",
|
["Scripts:"] = "UserPaths:Scripts;Reactor:System/Scripts",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Script = {
|
Script = {
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,6 @@ class CreateSaver(NewCreator):
|
||||||
instance_attributes = [
|
instance_attributes = [
|
||||||
"reviewable"
|
"reviewable"
|
||||||
]
|
]
|
||||||
default_variants = [
|
|
||||||
"Main",
|
|
||||||
"Mask"
|
|
||||||
]
|
|
||||||
|
|
||||||
# TODO: This should be renamed together with Nuke so it is aligned
|
# TODO: This should be renamed together with Nuke so it is aligned
|
||||||
temp_rendering_path_template = (
|
temp_rendering_path_template = (
|
||||||
|
|
@ -250,11 +246,7 @@ class CreateSaver(NewCreator):
|
||||||
label="Review",
|
label="Review",
|
||||||
)
|
)
|
||||||
|
|
||||||
def apply_settings(
|
def apply_settings(self, project_settings):
|
||||||
self,
|
|
||||||
project_settings,
|
|
||||||
system_settings
|
|
||||||
):
|
|
||||||
"""Method called on initialization of plugin to apply settings."""
|
"""Method called on initialization of plugin to apply settings."""
|
||||||
|
|
||||||
# plugin settings
|
# plugin settings
|
||||||
|
|
|
||||||
|
|
@ -296,7 +296,7 @@ class HoudiniCreator(NewCreator, HoudiniCreatorBase):
|
||||||
"""
|
"""
|
||||||
return [hou.ropNodeTypeCategory()]
|
return [hou.ropNodeTypeCategory()]
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
"""Method called on initialization of plugin to apply settings."""
|
"""Method called on initialization of plugin to apply settings."""
|
||||||
|
|
||||||
settings_name = self.settings_name
|
settings_name = self.settings_name
|
||||||
|
|
|
||||||
|
|
@ -260,7 +260,7 @@ class MayaCreator(NewCreator, MayaCreatorBase):
|
||||||
default=True)
|
default=True)
|
||||||
]
|
]
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
"""Method called on initialization of plugin to apply settings."""
|
"""Method called on initialization of plugin to apply settings."""
|
||||||
|
|
||||||
settings_name = self.settings_name
|
settings_name = self.settings_name
|
||||||
|
|
|
||||||
|
|
@ -81,10 +81,8 @@ class CreateAnimation(plugin.MayaHiddenCreator):
|
||||||
|
|
||||||
return defs
|
return defs
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
super(CreateAnimation, self).apply_settings(
|
super(CreateAnimation, self).apply_settings(project_settings)
|
||||||
project_settings, system_settings
|
|
||||||
)
|
|
||||||
# Hardcoding creator to be enabled due to existing settings would
|
# Hardcoding creator to be enabled due to existing settings would
|
||||||
# disable the creator causing the creator plugin to not be
|
# disable the creator causing the creator plugin to not be
|
||||||
# discoverable.
|
# discoverable.
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ class CreateRenderlayer(plugin.RenderlayerCreator):
|
||||||
render_settings = {}
|
render_settings = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def apply_settings(cls, project_settings, system_settings):
|
def apply_settings(cls, project_settings):
|
||||||
cls.render_settings = project_settings["maya"]["RenderSettings"]
|
cls.render_settings = project_settings["maya"]["RenderSettings"]
|
||||||
|
|
||||||
def create(self, subset_name, instance_data, pre_create_data):
|
def create(self, subset_name, instance_data, pre_create_data):
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class CreateUnrealSkeletalMesh(plugin.MayaCreator):
|
||||||
# Defined in settings
|
# Defined in settings
|
||||||
joint_hints = set()
|
joint_hints = set()
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
"""Apply project settings to creator"""
|
"""Apply project settings to creator"""
|
||||||
settings = (
|
settings = (
|
||||||
project_settings["maya"]["create"]["CreateUnrealSkeletalMesh"]
|
project_settings["maya"]["create"]["CreateUnrealSkeletalMesh"]
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ class CreateUnrealStaticMesh(plugin.MayaCreator):
|
||||||
# Defined in settings
|
# Defined in settings
|
||||||
collision_prefixes = []
|
collision_prefixes = []
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
"""Apply project settings to creator"""
|
"""Apply project settings to creator"""
|
||||||
settings = project_settings["maya"]["create"]["CreateUnrealStaticMesh"]
|
settings = project_settings["maya"]["create"]["CreateUnrealStaticMesh"]
|
||||||
self.collision_prefixes = settings["collision_prefixes"]
|
self.collision_prefixes = settings["collision_prefixes"]
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ class CreateVRayScene(plugin.RenderlayerCreator):
|
||||||
singleton_node_name = "vraysceneMain"
|
singleton_node_name = "vraysceneMain"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def apply_settings(cls, project_settings, system_settings):
|
def apply_settings(cls, project_settings):
|
||||||
cls.render_settings = project_settings["maya"]["RenderSettings"]
|
cls.render_settings = project_settings["maya"]["RenderSettings"]
|
||||||
|
|
||||||
def create(self, subset_name, instance_data, pre_create_data):
|
def create(self, subset_name, instance_data, pre_create_data):
|
||||||
|
|
|
||||||
|
|
@ -379,11 +379,7 @@ class NukeWriteCreator(NukeCreator):
|
||||||
sys.exc_info()[2]
|
sys.exc_info()[2]
|
||||||
)
|
)
|
||||||
|
|
||||||
def apply_settings(
|
def apply_settings(self, project_settings):
|
||||||
self,
|
|
||||||
project_settings,
|
|
||||||
system_settings
|
|
||||||
):
|
|
||||||
"""Method called on initialization of plugin to apply settings."""
|
"""Method called on initialization of plugin to apply settings."""
|
||||||
|
|
||||||
# plugin settings
|
# plugin settings
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ class AutoImageCreator(PSAutoCreator):
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings["photoshop"]["create"]["AutoImageCreator"]
|
project_settings["photoshop"]["create"]["AutoImageCreator"]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ class ImageCreator(Creator):
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings["photoshop"]["create"]["ImageCreator"]
|
project_settings["photoshop"]["create"]["ImageCreator"]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class ReviewCreator(PSAutoCreator):
|
||||||
it will get recreated in next publish either way).
|
it will get recreated in next publish either way).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings["photoshop"]["create"]["ReviewCreator"]
|
project_settings["photoshop"]["create"]["ReviewCreator"]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class WorkfileCreator(PSAutoCreator):
|
||||||
in next publish automatically).
|
in next publish automatically).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings["photoshop"]["create"]["WorkfileCreator"]
|
project_settings["photoshop"]["create"]["WorkfileCreator"]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class BatchMovieCreator(TrayPublishCreator):
|
||||||
# Position batch creator after simple creators
|
# Position batch creator after simple creators
|
||||||
order = 110
|
order = 110
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
creator_settings = (
|
creator_settings = (
|
||||||
project_settings["traypublisher"]["create"]["BatchMovieCreator"]
|
project_settings["traypublisher"]["create"]["BatchMovieCreator"]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ class CreateRenderlayer(TVPaintCreator):
|
||||||
# - Mark by default instance for review
|
# - Mark by default instance for review
|
||||||
mark_for_review = True
|
mark_for_review = True
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings["tvpaint"]["create"]["create_render_layer"]
|
project_settings["tvpaint"]["create"]["create_render_layer"]
|
||||||
)
|
)
|
||||||
|
|
@ -387,7 +387,7 @@ class CreateRenderPass(TVPaintCreator):
|
||||||
# Settings
|
# Settings
|
||||||
mark_for_review = True
|
mark_for_review = True
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings["tvpaint"]["create"]["create_render_pass"]
|
project_settings["tvpaint"]["create"]["create_render_pass"]
|
||||||
)
|
)
|
||||||
|
|
@ -690,7 +690,7 @@ class TVPaintAutoDetectRenderCreator(TVPaintCreator):
|
||||||
group_idx_offset = 10
|
group_idx_offset = 10
|
||||||
group_idx_padding = 3
|
group_idx_padding = 3
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings
|
project_settings
|
||||||
["tvpaint"]
|
["tvpaint"]
|
||||||
|
|
@ -1029,7 +1029,7 @@ class TVPaintSceneRenderCreator(TVPaintAutoCreator):
|
||||||
mark_for_review = True
|
mark_for_review = True
|
||||||
active_on_create = False
|
active_on_create = False
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings["tvpaint"]["create"]["create_render_scene"]
|
project_settings["tvpaint"]["create"]["create_render_scene"]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ class TVPaintReviewCreator(TVPaintAutoCreator):
|
||||||
# Settings
|
# Settings
|
||||||
active_on_create = True
|
active_on_create = True
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings["tvpaint"]["create"]["create_review"]
|
project_settings["tvpaint"]["create"]["create_review"]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ class TVPaintWorkfileCreator(TVPaintAutoCreator):
|
||||||
label = "Workfile"
|
label = "Workfile"
|
||||||
icon = "fa.file-o"
|
icon = "fa.file-o"
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
def apply_settings(self, project_settings):
|
||||||
plugin_settings = (
|
plugin_settings = (
|
||||||
project_settings["tvpaint"]["create"]["create_workfile"]
|
project_settings["tvpaint"]["create"]["create_workfile"]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -424,17 +424,25 @@ class TextDef(AbstractAttrDef):
|
||||||
|
|
||||||
|
|
||||||
class EnumDef(AbstractAttrDef):
|
class EnumDef(AbstractAttrDef):
|
||||||
"""Enumeration of single item from items.
|
"""Enumeration of items.
|
||||||
|
|
||||||
|
Enumeration of single item from items. Or list of items if multiselection
|
||||||
|
is enabled.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
items: Items definition that can be converted using
|
items (Union[list[str], list[dict[str, Any]]): Items definition that
|
||||||
'prepare_enum_items'.
|
can be converted using 'prepare_enum_items'.
|
||||||
default: Default value. Must be one key(value) from passed items.
|
default (Optional[Any]): Default value. Must be one key(value) from
|
||||||
|
passed items or list of values for multiselection.
|
||||||
|
multiselection (Optional[bool]): If True, multiselection is allowed.
|
||||||
|
Output is list of selected items.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type = "enum"
|
type = "enum"
|
||||||
|
|
||||||
def __init__(self, key, items, default=None, **kwargs):
|
def __init__(
|
||||||
|
self, key, items, default=None, multiselection=False, **kwargs
|
||||||
|
):
|
||||||
if not items:
|
if not items:
|
||||||
raise ValueError((
|
raise ValueError((
|
||||||
"Empty 'items' value. {} must have"
|
"Empty 'items' value. {} must have"
|
||||||
|
|
@ -443,30 +451,44 @@ class EnumDef(AbstractAttrDef):
|
||||||
|
|
||||||
items = self.prepare_enum_items(items)
|
items = self.prepare_enum_items(items)
|
||||||
item_values = [item["value"] for item in items]
|
item_values = [item["value"] for item in items]
|
||||||
if default not in item_values:
|
item_values_set = set(item_values)
|
||||||
for value in item_values:
|
if multiselection:
|
||||||
default = value
|
if default is None:
|
||||||
break
|
default = []
|
||||||
|
default = list(item_values_set.intersection(default))
|
||||||
|
|
||||||
|
elif default not in item_values:
|
||||||
|
default = next(iter(item_values), None)
|
||||||
|
|
||||||
super(EnumDef, self).__init__(key, default=default, **kwargs)
|
super(EnumDef, self).__init__(key, default=default, **kwargs)
|
||||||
|
|
||||||
self.items = items
|
self.items = items
|
||||||
self._item_values = set(item_values)
|
self._item_values = item_values_set
|
||||||
|
self.multiselection = multiselection
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if not super(EnumDef, self).__eq__(other):
|
if not super(EnumDef, self).__eq__(other):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return self.items == other.items
|
return (
|
||||||
|
self.items == other.items
|
||||||
|
and self.multiselection == other.multiselection
|
||||||
|
)
|
||||||
|
|
||||||
def convert_value(self, value):
|
def convert_value(self, value):
|
||||||
if value in self._item_values:
|
if not self.multiselection:
|
||||||
return value
|
if value in self._item_values:
|
||||||
return self.default
|
return value
|
||||||
|
return self.default
|
||||||
|
|
||||||
|
if value is None:
|
||||||
|
return copy.deepcopy(self.default)
|
||||||
|
return list(self._item_values.intersection(value))
|
||||||
|
|
||||||
def serialize(self):
|
def serialize(self):
|
||||||
data = super(EnumDef, self).serialize()
|
data = super(EnumDef, self).serialize()
|
||||||
data["items"] = copy.deepcopy(self.items)
|
data["items"] = copy.deepcopy(self.items)
|
||||||
|
data["multiselection"] = self.multiselection
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
||||||
|
|
@ -270,8 +270,8 @@ def is_func_signature_supported(func, *args, **kwargs):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
func (function): A function where the signature should be tested.
|
func (function): A function where the signature should be tested.
|
||||||
*args (tuple[Any]): Positional arguments for function signature.
|
*args (Any): Positional arguments for function signature.
|
||||||
**kwargs (dict[str, Any]): Keyword arguments for function signature.
|
**kwargs (Any): Keyword arguments for function signature.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: Function can pass in arguments.
|
bool: Function can pass in arguments.
|
||||||
|
|
|
||||||
|
|
@ -334,12 +334,6 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline,
|
||||||
|
|
||||||
payload = self._get_vray_render_payload(payload_data)
|
payload = self._get_vray_render_payload(payload_data)
|
||||||
|
|
||||||
elif "assscene" in instance.data["families"]:
|
|
||||||
self.log.debug("Submitting Arnold .ass standalone render..")
|
|
||||||
ass_export_payload = self._get_arnold_export_payload(payload_data)
|
|
||||||
export_job = self.submit(ass_export_payload)
|
|
||||||
|
|
||||||
payload = self._get_arnold_render_payload(payload_data)
|
|
||||||
else:
|
else:
|
||||||
self.log.debug("Submitting MayaBatch render..")
|
self.log.debug("Submitting MayaBatch render..")
|
||||||
payload = self._get_maya_payload(payload_data)
|
payload = self._get_maya_payload(payload_data)
|
||||||
|
|
@ -635,53 +629,6 @@ class MayaSubmitDeadline(abstract_submit_deadline.AbstractSubmitDeadline,
|
||||||
|
|
||||||
return job_info, attr.asdict(plugin_info)
|
return job_info, attr.asdict(plugin_info)
|
||||||
|
|
||||||
def _get_arnold_export_payload(self, data):
|
|
||||||
|
|
||||||
try:
|
|
||||||
from openpype.scripts import export_maya_ass_job
|
|
||||||
except Exception:
|
|
||||||
raise AssertionError(
|
|
||||||
"Expected module 'export_maya_ass_job' to be available")
|
|
||||||
|
|
||||||
module_path = export_maya_ass_job.__file__
|
|
||||||
if module_path.endswith(".pyc"):
|
|
||||||
module_path = module_path[: -len(".pyc")] + ".py"
|
|
||||||
|
|
||||||
script = os.path.normpath(module_path)
|
|
||||||
|
|
||||||
job_info = copy.deepcopy(self.job_info)
|
|
||||||
job_info.Name = self._job_info_label("Export")
|
|
||||||
|
|
||||||
# Force a single frame Python job
|
|
||||||
job_info.Plugin = "Python"
|
|
||||||
job_info.Frames = 1
|
|
||||||
|
|
||||||
renderlayer = self._instance.data["setMembers"]
|
|
||||||
|
|
||||||
# add required env vars for the export script
|
|
||||||
envs = {
|
|
||||||
"AVALON_APP_NAME": os.environ.get("AVALON_APP_NAME"),
|
|
||||||
"OPENPYPE_ASS_EXPORT_RENDER_LAYER": renderlayer,
|
|
||||||
"OPENPYPE_ASS_EXPORT_SCENE_FILE": self.scene_path,
|
|
||||||
"OPENPYPE_ASS_EXPORT_OUTPUT": job_info.OutputFilename[0],
|
|
||||||
"OPENPYPE_ASS_EXPORT_START": int(self._instance.data["frameStartHandle"]), # noqa
|
|
||||||
"OPENPYPE_ASS_EXPORT_END": int(self._instance.data["frameEndHandle"]), # noqa
|
|
||||||
"OPENPYPE_ASS_EXPORT_STEP": 1
|
|
||||||
}
|
|
||||||
for key, value in envs.items():
|
|
||||||
if not value:
|
|
||||||
continue
|
|
||||||
job_info.EnvironmentKeyValue[key] = value
|
|
||||||
|
|
||||||
plugin_info = PythonPluginInfo(
|
|
||||||
ScriptFile=script,
|
|
||||||
Version="3.6",
|
|
||||||
Arguments="",
|
|
||||||
SingleFrameOnly="True"
|
|
||||||
)
|
|
||||||
|
|
||||||
return job_info, attr.asdict(plugin_info)
|
|
||||||
|
|
||||||
def _get_vray_render_payload(self, data):
|
def _get_vray_render_payload(self, data):
|
||||||
|
|
||||||
# Job Info
|
# Job Info
|
||||||
|
|
|
||||||
|
|
@ -1774,7 +1774,7 @@ class CreateContext:
|
||||||
self.creator_discover_result = report
|
self.creator_discover_result = report
|
||||||
for creator_class in report.plugins:
|
for creator_class in report.plugins:
|
||||||
if inspect.isabstract(creator_class):
|
if inspect.isabstract(creator_class):
|
||||||
self.log.info(
|
self.log.debug(
|
||||||
"Skipping abstract Creator {}".format(str(creator_class))
|
"Skipping abstract Creator {}".format(str(creator_class))
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
@ -1804,6 +1804,7 @@ class CreateContext:
|
||||||
self,
|
self,
|
||||||
self.headless
|
self.headless
|
||||||
)
|
)
|
||||||
|
|
||||||
if not creator.enabled:
|
if not creator.enabled:
|
||||||
disabled_creators[creator_identifier] = creator
|
disabled_creators[creator_identifier] = creator
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,12 @@
|
||||||
import copy
|
import copy
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
from abc import (
|
from abc import ABCMeta, abstractmethod
|
||||||
ABCMeta,
|
|
||||||
abstractmethod,
|
|
||||||
abstractproperty
|
|
||||||
)
|
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from openpype.settings import get_system_settings, get_project_settings
|
from openpype.settings import get_system_settings, get_project_settings
|
||||||
from openpype.lib import Logger
|
from openpype.lib import Logger, is_func_signature_supported
|
||||||
from openpype.pipeline.plugin_discover import (
|
from openpype.pipeline.plugin_discover import (
|
||||||
discover,
|
discover,
|
||||||
register_plugin,
|
register_plugin,
|
||||||
|
|
@ -84,7 +80,8 @@ class SubsetConvertorPlugin(object):
|
||||||
def host(self):
|
def host(self):
|
||||||
return self._create_context.host
|
return self._create_context.host
|
||||||
|
|
||||||
@abstractproperty
|
@property
|
||||||
|
@abstractmethod
|
||||||
def identifier(self):
|
def identifier(self):
|
||||||
"""Converted identifier.
|
"""Converted identifier.
|
||||||
|
|
||||||
|
|
@ -161,7 +158,6 @@ class BaseCreator:
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
project_settings (Dict[str, Any]): Project settings.
|
project_settings (Dict[str, Any]): Project settings.
|
||||||
system_settings (Dict[str, Any]): System settings.
|
|
||||||
create_context (CreateContext): Context which initialized creator.
|
create_context (CreateContext): Context which initialized creator.
|
||||||
headless (bool): Running in headless mode.
|
headless (bool): Running in headless mode.
|
||||||
"""
|
"""
|
||||||
|
|
@ -208,10 +204,33 @@ class BaseCreator:
|
||||||
# - we may use UI inside processing this attribute should be checked
|
# - we may use UI inside processing this attribute should be checked
|
||||||
self.headless = headless
|
self.headless = headless
|
||||||
|
|
||||||
self.apply_settings(project_settings, system_settings)
|
expect_system_settings = False
|
||||||
|
if is_func_signature_supported(
|
||||||
|
self.apply_settings, project_settings
|
||||||
|
):
|
||||||
|
self.apply_settings(project_settings)
|
||||||
|
else:
|
||||||
|
expect_system_settings = True
|
||||||
|
# Backwards compatibility for system settings
|
||||||
|
self.apply_settings(project_settings, system_settings)
|
||||||
|
|
||||||
def apply_settings(self, project_settings, system_settings):
|
init_overriden = self.__class__.__init__ is not BaseCreator.__init__
|
||||||
"""Method called on initialization of plugin to apply settings."""
|
if init_overriden or expect_system_settings:
|
||||||
|
self.log.warning((
|
||||||
|
"WARNING: Source - Create plugin {}."
|
||||||
|
" System settings argument will not be passed to"
|
||||||
|
" '__init__' and 'apply_settings' methods in future versions"
|
||||||
|
" of OpenPype. Planned version to drop the support"
|
||||||
|
" is 3.16.6 or 3.17.0. Please contact Ynput core team if you"
|
||||||
|
" need to keep system settings."
|
||||||
|
).format(self.__class__.__name__))
|
||||||
|
|
||||||
|
def apply_settings(self, project_settings):
|
||||||
|
"""Method called on initialization of plugin to apply settings.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_settings (dict[str, Any]): Project settings.
|
||||||
|
"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -224,7 +243,8 @@ class BaseCreator:
|
||||||
|
|
||||||
return self.family
|
return self.family
|
||||||
|
|
||||||
@abstractproperty
|
@property
|
||||||
|
@abstractmethod
|
||||||
def family(self):
|
def family(self):
|
||||||
"""Family that plugin represents."""
|
"""Family that plugin represents."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
"""This module is used for command line exporting of ASS files.
|
|
||||||
|
|
||||||
WARNING:
|
|
||||||
This need to be rewriten to be able use it in Pype 3!
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import argparse
|
|
||||||
import logging
|
|
||||||
import subprocess
|
|
||||||
import platform
|
|
||||||
|
|
||||||
try:
|
|
||||||
from shutil import which
|
|
||||||
except ImportError:
|
|
||||||
# we are in python < 3.3
|
|
||||||
def which(command):
|
|
||||||
path = os.getenv('PATH')
|
|
||||||
for p in path.split(os.path.pathsep):
|
|
||||||
p = os.path.join(p, command)
|
|
||||||
if os.path.exists(p) and os.access(p, os.X_OK):
|
|
||||||
return p
|
|
||||||
|
|
||||||
handler = logging.basicConfig()
|
|
||||||
log = logging.getLogger("Publish Image Sequences")
|
|
||||||
log.setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
error_format = "Failed {plugin.__name__}: {error} -- {error.traceback}"
|
|
||||||
|
|
||||||
|
|
||||||
def __main__():
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument("--paths",
|
|
||||||
nargs="*",
|
|
||||||
default=[],
|
|
||||||
help="The filepaths to publish. This can be a "
|
|
||||||
"directory or a path to a .json publish "
|
|
||||||
"configuration.")
|
|
||||||
parser.add_argument("--gui",
|
|
||||||
default=False,
|
|
||||||
action="store_true",
|
|
||||||
help="Whether to run Pyblish in GUI mode.")
|
|
||||||
|
|
||||||
parser.add_argument("--pype", help="Pype root")
|
|
||||||
|
|
||||||
kwargs, args = parser.parse_known_args()
|
|
||||||
|
|
||||||
print("Running pype ...")
|
|
||||||
auto_pype_root = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
auto_pype_root = os.path.abspath(auto_pype_root + "../../../../..")
|
|
||||||
|
|
||||||
auto_pype_root = os.environ.get('OPENPYPE_SETUP_PATH') or auto_pype_root
|
|
||||||
if os.environ.get('OPENPYPE_SETUP_PATH'):
|
|
||||||
print("Got Pype location from environment: {}".format(
|
|
||||||
os.environ.get('OPENPYPE_SETUP_PATH')))
|
|
||||||
|
|
||||||
pype_command = "openpype.ps1"
|
|
||||||
if platform.system().lower() == "linux":
|
|
||||||
pype_command = "pype"
|
|
||||||
elif platform.system().lower() == "windows":
|
|
||||||
pype_command = "openpype.bat"
|
|
||||||
|
|
||||||
if kwargs.pype:
|
|
||||||
pype_root = kwargs.pype
|
|
||||||
else:
|
|
||||||
# test if pype.bat / pype is in the PATH
|
|
||||||
# if it is, which() will return its path and we use that.
|
|
||||||
# if not, we use auto_pype_root path. Caveat of that one is
|
|
||||||
# that it can be UNC path and that will not work on windows.
|
|
||||||
|
|
||||||
pype_path = which(pype_command)
|
|
||||||
|
|
||||||
if pype_path:
|
|
||||||
pype_root = os.path.dirname(pype_path)
|
|
||||||
else:
|
|
||||||
pype_root = auto_pype_root
|
|
||||||
|
|
||||||
print("Set pype root to: {}".format(pype_root))
|
|
||||||
print("Paths: {}".format(kwargs.paths or [os.getcwd()]))
|
|
||||||
|
|
||||||
# paths = kwargs.paths or [os.environ.get("OPENPYPE_METADATA_FILE")] or [os.getcwd()] # noqa
|
|
||||||
|
|
||||||
mayabatch = os.environ.get("AVALON_APP_NAME").replace("maya", "mayabatch")
|
|
||||||
args = [
|
|
||||||
os.path.join(pype_root, pype_command),
|
|
||||||
"launch",
|
|
||||||
"--app",
|
|
||||||
mayabatch,
|
|
||||||
"-script",
|
|
||||||
os.path.join(pype_root, "repos", "pype",
|
|
||||||
"pype", "scripts", "export_maya_ass_sequence.mel")
|
|
||||||
]
|
|
||||||
|
|
||||||
print("Pype command: {}".format(" ".join(args)))
|
|
||||||
# Forcing forwaring the environment because environment inheritance does
|
|
||||||
# not always work.
|
|
||||||
# Cast all values in environment to str to be safe
|
|
||||||
env = {k: str(v) for k, v in os.environ.items()}
|
|
||||||
exit_code = subprocess.call(args, env=env)
|
|
||||||
if exit_code != 0:
|
|
||||||
raise RuntimeError("Publishing failed.")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
__main__()
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
/*
|
|
||||||
Script to export specified layer as ass files.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
|
|
||||||
scene_file (str): Name of the scene to load.
|
|
||||||
start (int): Start frame.
|
|
||||||
end (int): End frame.
|
|
||||||
step (int): Step size.
|
|
||||||
output_path (str): File output path.
|
|
||||||
render_layer (str): Name of render layer.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
$scene_file=`getenv "OPENPYPE_ASS_EXPORT_SCENE_FILE"`;
|
|
||||||
$step=`getenv "OPENPYPE_ASS_EXPORT_STEP"`;
|
|
||||||
$start=`getenv "OPENPYPE_ASS_EXPORT_START"`;
|
|
||||||
$end=`getenv "OPENPYPE_ASS_EXPORT_END"`;
|
|
||||||
$file_path=`getenv "OPENPYPE_ASS_EXPORT_OUTPUT"`;
|
|
||||||
$render_layer = `getenv "OPENPYPE_ASS_EXPORT_RENDER_LAYER"`;
|
|
||||||
|
|
||||||
print("*** ASS Export Plugin\n");
|
|
||||||
|
|
||||||
if ($scene_file == "") {
|
|
||||||
print("!!! cannot determine scene file\n");
|
|
||||||
quit -a -ex -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($step == "") {
|
|
||||||
print("!!! cannot determine step size\n");
|
|
||||||
quit -a -ex -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($start == "") {
|
|
||||||
print("!!! cannot determine start frame\n");
|
|
||||||
quit -a -ex -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($end == "") {
|
|
||||||
print("!!! cannot determine end frame\n");
|
|
||||||
quit -a -ex -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($file_path == "") {
|
|
||||||
print("!!! cannot determine output file\n");
|
|
||||||
quit -a -ex -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($render_layer == "") {
|
|
||||||
print("!!! cannot determine render layer\n");
|
|
||||||
quit -a -ex -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
print(">>> Opening Scene [ " + $scene_file + " ]\n");
|
|
||||||
|
|
||||||
// open scene
|
|
||||||
file -o -f $scene_file;
|
|
||||||
|
|
||||||
// switch to render layer
|
|
||||||
print(">>> Switching layer [ "+ $render_layer + " ]\n");
|
|
||||||
editRenderLayerGlobals -currentRenderLayer $render_layer;
|
|
||||||
|
|
||||||
// export
|
|
||||||
print(">>> Exporting to [ " + $file_path + " ]\n");
|
|
||||||
arnoldExportAss -mask 255 -sl 1 -ll 1 -bb 1 -sf $start -se $end -b -fs $step;
|
|
||||||
print("--- Done\n");
|
|
||||||
|
|
@ -1,241 +0,0 @@
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from openpype.client import get_asset_by_name, get_versions
|
|
||||||
|
|
||||||
# Pipeline imports
|
|
||||||
from openpype.hosts.fusion import api
|
|
||||||
import openpype.hosts.fusion.api.lib as fusion_lib
|
|
||||||
|
|
||||||
# Config imports
|
|
||||||
from openpype.lib import version_up
|
|
||||||
from openpype.pipeline import (
|
|
||||||
install_host,
|
|
||||||
registered_host,
|
|
||||||
legacy_io,
|
|
||||||
get_current_project_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
from openpype.pipeline.context_tools import get_workdir_from_session
|
|
||||||
from openpype.pipeline.version_start import get_versioning_start
|
|
||||||
|
|
||||||
log = logging.getLogger("Update Slap Comp")
|
|
||||||
|
|
||||||
|
|
||||||
def _format_version_folder(folder):
|
|
||||||
"""Format a version folder based on the filepath
|
|
||||||
|
|
||||||
Args:
|
|
||||||
folder: file path to a folder
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: new version folder name
|
|
||||||
"""
|
|
||||||
|
|
||||||
new_version = get_versioning_start(
|
|
||||||
get_current_project_name(),
|
|
||||||
"fusion",
|
|
||||||
family="workfile"
|
|
||||||
)
|
|
||||||
if os.path.isdir(folder):
|
|
||||||
re_version = re.compile(r"v\d+$")
|
|
||||||
versions = [i for i in os.listdir(folder) if os.path.isdir(i)
|
|
||||||
and re_version.match(i)]
|
|
||||||
if versions:
|
|
||||||
# ensure the "v" is not included
|
|
||||||
new_version = int(max(versions)[1:]) + 1
|
|
||||||
|
|
||||||
version_folder = "v{:03d}".format(new_version)
|
|
||||||
|
|
||||||
return version_folder
|
|
||||||
|
|
||||||
|
|
||||||
def _get_fusion_instance():
|
|
||||||
fusion = getattr(sys.modules["__main__"], "fusion", None)
|
|
||||||
if fusion is None:
|
|
||||||
try:
|
|
||||||
# Support for FuScript.exe, BlackmagicFusion module for py2 only
|
|
||||||
import BlackmagicFusion as bmf
|
|
||||||
fusion = bmf.scriptapp("Fusion")
|
|
||||||
except ImportError:
|
|
||||||
raise RuntimeError("Could not find a Fusion instance")
|
|
||||||
return fusion
|
|
||||||
|
|
||||||
|
|
||||||
def _format_filepath(session):
|
|
||||||
|
|
||||||
project = session["AVALON_PROJECT"]
|
|
||||||
asset = session["AVALON_ASSET"]
|
|
||||||
|
|
||||||
# Save updated slap comp
|
|
||||||
work_path = get_workdir_from_session(session)
|
|
||||||
walk_to_dir = os.path.join(work_path, "scenes", "slapcomp")
|
|
||||||
slapcomp_dir = os.path.abspath(walk_to_dir)
|
|
||||||
|
|
||||||
# Ensure destination exists
|
|
||||||
if not os.path.isdir(slapcomp_dir):
|
|
||||||
log.warning("Folder did not exist, creating folder structure")
|
|
||||||
os.makedirs(slapcomp_dir)
|
|
||||||
|
|
||||||
# Compute output path
|
|
||||||
new_filename = "{}_{}_slapcomp_v001.comp".format(project, asset)
|
|
||||||
new_filepath = os.path.join(slapcomp_dir, new_filename)
|
|
||||||
|
|
||||||
# Create new unqiue filepath
|
|
||||||
if os.path.exists(new_filepath):
|
|
||||||
new_filepath = version_up(new_filepath)
|
|
||||||
|
|
||||||
return new_filepath
|
|
||||||
|
|
||||||
|
|
||||||
def _update_savers(comp, session):
|
|
||||||
"""Update all savers of the current comp to ensure the output is correct
|
|
||||||
|
|
||||||
Args:
|
|
||||||
comp (object): current comp instance
|
|
||||||
session (dict): the current Avalon session
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
None
|
|
||||||
"""
|
|
||||||
|
|
||||||
new_work = get_workdir_from_session(session)
|
|
||||||
renders = os.path.join(new_work, "renders")
|
|
||||||
version_folder = _format_version_folder(renders)
|
|
||||||
renders_version = os.path.join(renders, version_folder)
|
|
||||||
|
|
||||||
comp.Print("New renders to: %s\n" % renders)
|
|
||||||
|
|
||||||
with api.comp_lock_and_undo_chunk(comp):
|
|
||||||
savers = comp.GetToolList(False, "Saver").values()
|
|
||||||
for saver in savers:
|
|
||||||
filepath = saver.GetAttrs("TOOLST_Clip_Name")[1.0]
|
|
||||||
filename = os.path.basename(filepath)
|
|
||||||
new_path = os.path.join(renders_version, filename)
|
|
||||||
saver["Clip"] = new_path
|
|
||||||
|
|
||||||
|
|
||||||
def update_frame_range(comp, representations):
|
|
||||||
"""Update the frame range of the comp and render length
|
|
||||||
|
|
||||||
The start and end frame are based on the lowest start frame and the highest
|
|
||||||
end frame
|
|
||||||
|
|
||||||
Args:
|
|
||||||
comp (object): current focused comp
|
|
||||||
representations (list) collection of dicts
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
None
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
version_ids = [r["parent"] for r in representations]
|
|
||||||
project_name = get_current_project_name()
|
|
||||||
versions = list(get_versions(project_name, version_ids=version_ids))
|
|
||||||
|
|
||||||
start = min(v["data"]["frameStart"] for v in versions)
|
|
||||||
end = max(v["data"]["frameEnd"] for v in versions)
|
|
||||||
|
|
||||||
fusion_lib.update_frame_range(start, end, comp=comp)
|
|
||||||
|
|
||||||
|
|
||||||
def switch(asset_name, filepath=None, new=True):
|
|
||||||
"""Switch the current containers of the file to the other asset (shot)
|
|
||||||
|
|
||||||
Args:
|
|
||||||
filepath (str): file path of the comp file
|
|
||||||
asset_name (str): name of the asset (shot)
|
|
||||||
new (bool): Save updated comp under a different name
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
comp path (str): new filepath of the updated comp
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# If filepath provided, ensure it is valid absolute path
|
|
||||||
if filepath is not None:
|
|
||||||
if not os.path.isabs(filepath):
|
|
||||||
filepath = os.path.abspath(filepath)
|
|
||||||
|
|
||||||
assert os.path.exists(filepath), "%s must exist " % filepath
|
|
||||||
|
|
||||||
# Assert asset name exists
|
|
||||||
# It is better to do this here then to wait till switch_shot does it
|
|
||||||
project_name = get_current_project_name()
|
|
||||||
asset = get_asset_by_name(project_name, asset_name)
|
|
||||||
assert asset, "Could not find '%s' in the database" % asset_name
|
|
||||||
|
|
||||||
# Go to comp
|
|
||||||
if not filepath:
|
|
||||||
current_comp = api.get_current_comp()
|
|
||||||
assert current_comp is not None, "Could not find current comp"
|
|
||||||
else:
|
|
||||||
fusion = _get_fusion_instance()
|
|
||||||
current_comp = fusion.LoadComp(filepath, quiet=True)
|
|
||||||
assert current_comp is not None, "Fusion could not load '%s'" % filepath
|
|
||||||
|
|
||||||
host = registered_host()
|
|
||||||
containers = list(host.ls())
|
|
||||||
assert containers, "Nothing to update"
|
|
||||||
|
|
||||||
representations = []
|
|
||||||
for container in containers:
|
|
||||||
try:
|
|
||||||
representation = fusion_lib.switch_item(container,
|
|
||||||
asset_name=asset_name)
|
|
||||||
representations.append(representation)
|
|
||||||
except Exception as e:
|
|
||||||
current_comp.Print("Error in switching! %s\n" % e.message)
|
|
||||||
|
|
||||||
message = "Switched %i Loaders of the %i\n" % (len(representations),
|
|
||||||
len(containers))
|
|
||||||
current_comp.Print(message)
|
|
||||||
|
|
||||||
# Build the session to switch to
|
|
||||||
switch_to_session = legacy_io.Session.copy()
|
|
||||||
switch_to_session["AVALON_ASSET"] = asset['name']
|
|
||||||
|
|
||||||
if new:
|
|
||||||
comp_path = _format_filepath(switch_to_session)
|
|
||||||
|
|
||||||
# Update savers output based on new session
|
|
||||||
_update_savers(current_comp, switch_to_session)
|
|
||||||
else:
|
|
||||||
comp_path = version_up(filepath)
|
|
||||||
|
|
||||||
current_comp.Print(comp_path)
|
|
||||||
|
|
||||||
current_comp.Print("\nUpdating frame range")
|
|
||||||
update_frame_range(current_comp, representations)
|
|
||||||
|
|
||||||
current_comp.Save(comp_path)
|
|
||||||
|
|
||||||
return comp_path
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="Switch to a shot within an"
|
|
||||||
"existing comp file")
|
|
||||||
|
|
||||||
parser.add_argument("--file_path",
|
|
||||||
type=str,
|
|
||||||
default=True,
|
|
||||||
help="File path of the comp to use")
|
|
||||||
|
|
||||||
parser.add_argument("--asset_name",
|
|
||||||
type=str,
|
|
||||||
default=True,
|
|
||||||
help="Name of the asset (shot) to switch")
|
|
||||||
|
|
||||||
args, unknown = parser.parse_args()
|
|
||||||
|
|
||||||
install_host(api)
|
|
||||||
switch(args.asset_name, args.file_path)
|
|
||||||
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
@ -19,6 +19,7 @@ from openpype.tools.utils import (
|
||||||
CustomTextComboBox,
|
CustomTextComboBox,
|
||||||
FocusSpinBox,
|
FocusSpinBox,
|
||||||
FocusDoubleSpinBox,
|
FocusDoubleSpinBox,
|
||||||
|
MultiSelectionComboBox,
|
||||||
)
|
)
|
||||||
from openpype.widgets.nice_checkbox import NiceCheckbox
|
from openpype.widgets.nice_checkbox import NiceCheckbox
|
||||||
|
|
||||||
|
|
@ -412,10 +413,19 @@ class EnumAttrWidget(_BaseAttrDefWidget):
|
||||||
self._multivalue = False
|
self._multivalue = False
|
||||||
super(EnumAttrWidget, self).__init__(*args, **kwargs)
|
super(EnumAttrWidget, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def multiselection(self):
|
||||||
|
return self.attr_def.multiselection
|
||||||
|
|
||||||
def _ui_init(self):
|
def _ui_init(self):
|
||||||
input_widget = CustomTextComboBox(self)
|
if self.multiselection:
|
||||||
combo_delegate = QtWidgets.QStyledItemDelegate(input_widget)
|
input_widget = MultiSelectionComboBox(self)
|
||||||
input_widget.setItemDelegate(combo_delegate)
|
|
||||||
|
else:
|
||||||
|
input_widget = CustomTextComboBox(self)
|
||||||
|
combo_delegate = QtWidgets.QStyledItemDelegate(input_widget)
|
||||||
|
input_widget.setItemDelegate(combo_delegate)
|
||||||
|
self._combo_delegate = combo_delegate
|
||||||
|
|
||||||
if self.attr_def.tooltip:
|
if self.attr_def.tooltip:
|
||||||
input_widget.setToolTip(self.attr_def.tooltip)
|
input_widget.setToolTip(self.attr_def.tooltip)
|
||||||
|
|
@ -427,9 +437,11 @@ class EnumAttrWidget(_BaseAttrDefWidget):
|
||||||
if idx >= 0:
|
if idx >= 0:
|
||||||
input_widget.setCurrentIndex(idx)
|
input_widget.setCurrentIndex(idx)
|
||||||
|
|
||||||
input_widget.currentIndexChanged.connect(self._on_value_change)
|
if self.multiselection:
|
||||||
|
input_widget.value_changed.connect(self._on_value_change)
|
||||||
|
else:
|
||||||
|
input_widget.currentIndexChanged.connect(self._on_value_change)
|
||||||
|
|
||||||
self._combo_delegate = combo_delegate
|
|
||||||
self._input_widget = input_widget
|
self._input_widget = input_widget
|
||||||
|
|
||||||
self.main_layout.addWidget(input_widget, 0)
|
self.main_layout.addWidget(input_widget, 0)
|
||||||
|
|
@ -442,17 +454,40 @@ class EnumAttrWidget(_BaseAttrDefWidget):
|
||||||
self.value_changed.emit(new_value, self.attr_def.id)
|
self.value_changed.emit(new_value, self.attr_def.id)
|
||||||
|
|
||||||
def current_value(self):
|
def current_value(self):
|
||||||
|
if self.multiselection:
|
||||||
|
return self._input_widget.value()
|
||||||
idx = self._input_widget.currentIndex()
|
idx = self._input_widget.currentIndex()
|
||||||
return self._input_widget.itemData(idx)
|
return self._input_widget.itemData(idx)
|
||||||
|
|
||||||
|
def _multiselection_multivalue_prep(self, values):
|
||||||
|
final = None
|
||||||
|
multivalue = False
|
||||||
|
for value in values:
|
||||||
|
value = set(value)
|
||||||
|
if final is None:
|
||||||
|
final = value
|
||||||
|
elif multivalue or final != value:
|
||||||
|
final |= value
|
||||||
|
multivalue = True
|
||||||
|
return list(final), multivalue
|
||||||
|
|
||||||
def set_value(self, value, multivalue=False):
|
def set_value(self, value, multivalue=False):
|
||||||
if multivalue:
|
if multivalue:
|
||||||
set_value = set(value)
|
if self.multiselection:
|
||||||
if len(set_value) == 1:
|
value, multivalue = self._multiselection_multivalue_prep(
|
||||||
multivalue = False
|
value)
|
||||||
value = tuple(set_value)[0]
|
else:
|
||||||
|
set_value = set(value)
|
||||||
|
if len(set_value) == 1:
|
||||||
|
multivalue = False
|
||||||
|
value = tuple(set_value)[0]
|
||||||
|
|
||||||
if not multivalue:
|
if self.multiselection:
|
||||||
|
self._input_widget.blockSignals(True)
|
||||||
|
self._input_widget.set_value(value)
|
||||||
|
self._input_widget.blockSignals(False)
|
||||||
|
|
||||||
|
elif not multivalue:
|
||||||
idx = self._input_widget.findData(value)
|
idx = self._input_widget.findData(value)
|
||||||
cur_idx = self._input_widget.currentIndex()
|
cur_idx = self._input_widget.currentIndex()
|
||||||
if idx != cur_idx and idx >= 0:
|
if idx != cur_idx and idx >= 0:
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ from qtpy import QtWidgets, QtCore, QtGui
|
||||||
|
|
||||||
from openpype.widgets.sliders import NiceSlider
|
from openpype.widgets.sliders import NiceSlider
|
||||||
from openpype.tools.settings import CHILD_OFFSET
|
from openpype.tools.settings import CHILD_OFFSET
|
||||||
|
from openpype.tools.utils import MultiSelectionComboBox
|
||||||
from openpype.settings.entities.exceptions import BaseInvalidValue
|
from openpype.settings.entities.exceptions import BaseInvalidValue
|
||||||
|
|
||||||
from .widgets import (
|
from .widgets import (
|
||||||
|
|
@ -15,7 +16,6 @@ from .widgets import (
|
||||||
SettingsNiceCheckbox,
|
SettingsNiceCheckbox,
|
||||||
SettingsLineEdit
|
SettingsLineEdit
|
||||||
)
|
)
|
||||||
from .multiselection_combobox import MultiSelectionComboBox
|
|
||||||
from .wrapper_widgets import (
|
from .wrapper_widgets import (
|
||||||
WrapperWidget,
|
WrapperWidget,
|
||||||
CollapsibleWrapper,
|
CollapsibleWrapper,
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ from .models import (
|
||||||
from .overlay_messages import (
|
from .overlay_messages import (
|
||||||
MessageOverlayObject,
|
MessageOverlayObject,
|
||||||
)
|
)
|
||||||
|
from .multiselection_combobox import MultiSelectionComboBox
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
|
@ -78,4 +79,6 @@ __all__ = (
|
||||||
"RecursiveSortFilterProxyModel",
|
"RecursiveSortFilterProxyModel",
|
||||||
|
|
||||||
"MessageOverlayObject",
|
"MessageOverlayObject",
|
||||||
|
|
||||||
|
"MultiSelectionComboBox",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -170,8 +170,12 @@ def get_openpype_qt_app():
|
||||||
if attr is not None:
|
if attr is not None:
|
||||||
QtWidgets.QApplication.setAttribute(attr)
|
QtWidgets.QApplication.setAttribute(attr)
|
||||||
|
|
||||||
if hasattr(
|
policy = os.getenv("QT_SCALE_FACTOR_ROUNDING_POLICY")
|
||||||
QtWidgets.QApplication, "setHighDpiScaleFactorRoundingPolicy"
|
if (
|
||||||
|
hasattr(
|
||||||
|
QtWidgets.QApplication, "setHighDpiScaleFactorRoundingPolicy"
|
||||||
|
)
|
||||||
|
and not policy
|
||||||
):
|
):
|
||||||
QtWidgets.QApplication.setHighDpiScaleFactorRoundingPolicy(
|
QtWidgets.QApplication.setHighDpiScaleFactorRoundingPolicy(
|
||||||
QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
|
QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
from qtpy import QtCore, QtGui, QtWidgets
|
from qtpy import QtCore, QtGui, QtWidgets
|
||||||
from openpype.tools.utils.lib import (
|
|
||||||
|
from .lib import (
|
||||||
checkstate_int_to_enum,
|
checkstate_int_to_enum,
|
||||||
checkstate_enum_to_int,
|
checkstate_enum_to_int,
|
||||||
)
|
)
|
||||||
from openpype.tools.utils.constants import (
|
from .constants import (
|
||||||
CHECKED_INT,
|
CHECKED_INT,
|
||||||
UNCHECKED_INT,
|
UNCHECKED_INT,
|
||||||
ITEM_IS_USER_TRISTATE,
|
ITEM_IS_USER_TRISTATE,
|
||||||
|
|
@ -60,12 +61,25 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
||||||
self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True)
|
self._block_mouse_release_timer = QtCore.QTimer(self, singleShot=True)
|
||||||
self._initial_mouse_pos = None
|
self._initial_mouse_pos = None
|
||||||
self._separator = separator
|
self._separator = separator
|
||||||
self.placeholder_text = placeholder
|
self._placeholder_text = placeholder
|
||||||
self.delegate = ComboItemDelegate(self)
|
delegate = ComboItemDelegate(self)
|
||||||
self.setItemDelegate(self.delegate)
|
self.setItemDelegate(delegate)
|
||||||
|
|
||||||
self.lines = {}
|
self._lines = {}
|
||||||
self.item_height = None
|
self._item_height = None
|
||||||
|
self._custom_text = None
|
||||||
|
self._delegate = delegate
|
||||||
|
|
||||||
|
def get_placeholder_text(self):
|
||||||
|
return self._placeholder_text
|
||||||
|
|
||||||
|
def set_placeholder_text(self, text):
|
||||||
|
self._placeholder_text = text
|
||||||
|
self._update_size_hint()
|
||||||
|
|
||||||
|
def set_custom_text(self, text):
|
||||||
|
self._custom_text = text
|
||||||
|
self._update_size_hint()
|
||||||
|
|
||||||
def focusInEvent(self, event):
|
def focusInEvent(self, event):
|
||||||
self.focused_in.emit()
|
self.focused_in.emit()
|
||||||
|
|
@ -158,7 +172,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
||||||
if new_state is not None:
|
if new_state is not None:
|
||||||
model.setData(current_index, new_state, QtCore.Qt.CheckStateRole)
|
model.setData(current_index, new_state, QtCore.Qt.CheckStateRole)
|
||||||
self.view().update(current_index)
|
self.view().update(current_index)
|
||||||
self.update_size_hint()
|
self._update_size_hint()
|
||||||
self.value_changed.emit()
|
self.value_changed.emit()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
@ -182,25 +196,33 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
||||||
self.initStyleOption(option)
|
self.initStyleOption(option)
|
||||||
painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, option)
|
painter.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, option)
|
||||||
|
|
||||||
# draw the icon and text
|
|
||||||
items = self.checked_items_text()
|
items = self.checked_items_text()
|
||||||
if not items:
|
# draw the icon and text
|
||||||
option.currentText = self.placeholder_text
|
draw_text = True
|
||||||
|
combotext = None
|
||||||
|
if self._custom_text is not None:
|
||||||
|
combotext = self._custom_text
|
||||||
|
elif not items:
|
||||||
|
combotext = self._placeholder_text
|
||||||
|
else:
|
||||||
|
draw_text = False
|
||||||
|
if draw_text:
|
||||||
|
option.currentText = combotext
|
||||||
option.palette.setCurrentColorGroup(QtGui.QPalette.Disabled)
|
option.palette.setCurrentColorGroup(QtGui.QPalette.Disabled)
|
||||||
painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option)
|
painter.drawControl(QtWidgets.QStyle.CE_ComboBoxLabel, option)
|
||||||
return
|
return
|
||||||
|
|
||||||
font_metricts = self.fontMetrics()
|
font_metricts = self.fontMetrics()
|
||||||
|
|
||||||
if self.item_height is None:
|
if self._item_height is None:
|
||||||
self.updateGeometry()
|
self.updateGeometry()
|
||||||
self.update()
|
self.update()
|
||||||
return
|
return
|
||||||
|
|
||||||
for line, items in self.lines.items():
|
for line, items in self._lines.items():
|
||||||
top_y = (
|
top_y = (
|
||||||
option.rect.top()
|
option.rect.top()
|
||||||
+ (line * self.item_height)
|
+ (line * self._item_height)
|
||||||
+ self.top_bottom_margins
|
+ self.top_bottom_margins
|
||||||
)
|
)
|
||||||
left_x = option.rect.left() + self.left_offset
|
left_x = option.rect.left() + self.left_offset
|
||||||
|
|
@ -210,7 +232,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
||||||
|
|
||||||
label_rect.moveTop(top_y)
|
label_rect.moveTop(top_y)
|
||||||
label_rect.moveLeft(left_x)
|
label_rect.moveLeft(left_x)
|
||||||
label_rect.setHeight(self.item_height)
|
label_rect.setHeight(self._item_height)
|
||||||
label_rect.setWidth(
|
label_rect.setWidth(
|
||||||
label_rect.width() + self.left_right_padding
|
label_rect.width() + self.left_right_padding
|
||||||
)
|
)
|
||||||
|
|
@ -239,14 +261,18 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
||||||
|
|
||||||
def resizeEvent(self, *args, **kwargs):
|
def resizeEvent(self, *args, **kwargs):
|
||||||
super(MultiSelectionComboBox, self).resizeEvent(*args, **kwargs)
|
super(MultiSelectionComboBox, self).resizeEvent(*args, **kwargs)
|
||||||
self.update_size_hint()
|
self._update_size_hint()
|
||||||
|
|
||||||
def update_size_hint(self):
|
def _update_size_hint(self):
|
||||||
self.lines = {}
|
if self._custom_text is not None:
|
||||||
|
self.update()
|
||||||
|
return
|
||||||
|
self._lines = {}
|
||||||
|
|
||||||
items = self.checked_items_text()
|
items = self.checked_items_text()
|
||||||
if not items:
|
if not items:
|
||||||
self.update()
|
self.update()
|
||||||
|
self.repaint()
|
||||||
return
|
return
|
||||||
|
|
||||||
option = QtWidgets.QStyleOptionComboBox()
|
option = QtWidgets.QStyleOptionComboBox()
|
||||||
|
|
@ -259,7 +285,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
||||||
total_width = option.rect.width() - btn_rect.width()
|
total_width = option.rect.width() - btn_rect.width()
|
||||||
|
|
||||||
line = 0
|
line = 0
|
||||||
self.lines = {line: []}
|
self._lines = {line: []}
|
||||||
|
|
||||||
font_metricts = self.fontMetrics()
|
font_metricts = self.fontMetrics()
|
||||||
default_left_x = 0 + self.left_offset
|
default_left_x = 0 + self.left_offset
|
||||||
|
|
@ -270,18 +296,18 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
||||||
right_x = left_x + width
|
right_x = left_x + width
|
||||||
if right_x > total_width:
|
if right_x > total_width:
|
||||||
left_x = int(default_left_x)
|
left_x = int(default_left_x)
|
||||||
if self.lines.get(line):
|
if self._lines.get(line):
|
||||||
line += 1
|
line += 1
|
||||||
self.lines[line] = [item]
|
self._lines[line] = [item]
|
||||||
left_x += width
|
left_x += width
|
||||||
else:
|
else:
|
||||||
self.lines[line] = [item]
|
self._lines[line] = [item]
|
||||||
line += 1
|
line += 1
|
||||||
else:
|
else:
|
||||||
if line in self.lines:
|
if line in self._lines:
|
||||||
self.lines[line].append(item)
|
self._lines[line].append(item)
|
||||||
else:
|
else:
|
||||||
self.lines[line] = [item]
|
self._lines[line] = [item]
|
||||||
left_x = left_x + width + self.item_spacing
|
left_x = left_x + width + self.item_spacing
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
@ -289,18 +315,20 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
||||||
|
|
||||||
def sizeHint(self):
|
def sizeHint(self):
|
||||||
value = super(MultiSelectionComboBox, self).sizeHint()
|
value = super(MultiSelectionComboBox, self).sizeHint()
|
||||||
lines = len(self.lines)
|
lines = 1
|
||||||
if lines == 0:
|
if self._custom_text is None:
|
||||||
lines = 1
|
lines = len(self._lines)
|
||||||
|
if lines == 0:
|
||||||
|
lines = 1
|
||||||
|
|
||||||
if self.item_height is None:
|
if self._item_height is None:
|
||||||
self.item_height = (
|
self._item_height = (
|
||||||
self.fontMetrics().height()
|
self.fontMetrics().height()
|
||||||
+ (2 * self.top_bottom_padding)
|
+ (2 * self.top_bottom_padding)
|
||||||
+ (2 * self.top_bottom_margins)
|
+ (2 * self.top_bottom_margins)
|
||||||
)
|
)
|
||||||
value.setHeight(
|
value.setHeight(
|
||||||
(lines * self.item_height)
|
(lines * self._item_height)
|
||||||
+ (2 * self.top_bottom_margins)
|
+ (2 * self.top_bottom_margins)
|
||||||
)
|
)
|
||||||
return value
|
return value
|
||||||
|
|
@ -316,7 +344,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
||||||
else:
|
else:
|
||||||
check_state = UNCHECKED_INT
|
check_state = UNCHECKED_INT
|
||||||
self.setItemData(idx, check_state, QtCore.Qt.CheckStateRole)
|
self.setItemData(idx, check_state, QtCore.Qt.CheckStateRole)
|
||||||
self.update_size_hint()
|
self._update_size_hint()
|
||||||
|
|
||||||
def value(self):
|
def value(self):
|
||||||
items = list()
|
items = list()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue