[Automated] Merged develop into main

This commit is contained in:
pypebot 2022-03-16 04:30:04 +01:00 committed by GitHub
commit d27f413bfd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 380 additions and 236 deletions

View file

@ -5,7 +5,6 @@ import platform
import functools
import logging
from openpype.pipeline import LegacyCreator
from .settings import get_project_settings
from .lib import (
Anatomy,
@ -76,6 +75,7 @@ def install():
"""Install Pype to Avalon."""
from pyblish.lib import MessageHandler
from openpype.modules import load_modules
from openpype.pipeline import LegacyCreator
from avalon import pipeline
# Make sure modules are loaded

View file

@ -272,8 +272,8 @@ function Client() {
app.avalonClient.send(
{
'module': 'avalon.api',
'method': 'emit',
'module': 'openpype.lib',
'method': 'emit_event',
'args': ['application.launched']
}, false);
};

View file

@ -178,7 +178,7 @@ class ReferenceLoader(Loader):
loader=self.__class__.__name__
)
loaded_containers.append(container)
self._organize_containers([ref_node], container)
self._organize_containers(nodes, container)
c += 1
namespace = None
@ -247,6 +247,8 @@ class ReferenceLoader(Loader):
self.log.warning("Ignoring file read error:\n%s", exc)
self._organize_containers(content, container["objectName"])
# Reapply alembic settings.
if representation["name"] == "abc" and alembic_data:
alembic_nodes = cmds.ls(
@ -284,7 +286,6 @@ class ReferenceLoader(Loader):
to remove from scene.
"""
from maya import cmds
node = container["objectName"]
@ -318,6 +319,7 @@ class ReferenceLoader(Loader):
@staticmethod
def _organize_containers(nodes, container):
# type: (list, str) -> None
"""Put containers in loaded data to correct hierarchy."""
for node in nodes:
id_attr = "{}.id".format(node)
if not cmds.attributeQuery("id", node=node, exists=True):

View file

@ -121,18 +121,10 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader):
if family == "rig":
self._post_process_rig(name, namespace, context, options)
else:
if "translate" in options:
cmds.setAttr(group_name + ".t", *options["translate"])
return new_nodes
def load(self, context, name=None, namespace=None, options=None):
container = super(ReferenceLoader, self).load(
context, name, namespace, options)
# clean containers if present to AVALON_CONTAINERS
self._organize_containers(self[:], container[0])
def switch(self, container, representation):
self.update(container, representation)

View file

@ -58,16 +58,11 @@ class ExtractMayaSceneRaw(openpype.api.Extractor):
else:
members = instance[:]
loaded_containers = None
if set(self.add_for_families).intersection(
set(instance.data.get("families")),
set(instance.data.get("family").lower())):
loaded_containers = self._add_loaded_containers(members)
selection = members
if loaded_containers:
self.log.info(loaded_containers)
selection += loaded_containers
if set(self.add_for_families).intersection(
set(instance.data.get("families", []))) or \
instance.data.get("family") in self.add_for_families:
selection += self._get_loaded_containers(members)
# Perform extraction
self.log.info("Performing extraction ...")
@ -97,15 +92,15 @@ class ExtractMayaSceneRaw(openpype.api.Extractor):
self.log.info("Extracted instance '%s' to: %s" % (instance.name, path))
@staticmethod
def _add_loaded_containers(members):
def _get_loaded_containers(members):
# type: (list) -> list
refs_to_include = [
cmds.referenceQuery(ref, referenceNode=True)
for ref in members
if cmds.referenceQuery(ref, isNodeReferenced=True)
]
refs_to_include = {
cmds.referenceQuery(node, referenceNode=True)
for node in members
if cmds.referenceQuery(node, isNodeReferenced=True)
}
refs_to_include = set(refs_to_include)
members_with_refs = refs_to_include.union(members)
obj_sets = cmds.ls("*.id", long=True, type="objectSet", recursive=True,
objectsOnly=True)
@ -121,7 +116,7 @@ class ExtractMayaSceneRaw(openpype.api.Extractor):
continue
set_content = set(cmds.sets(obj_set, query=True))
if set_content.intersection(refs_to_include):
if set_content.intersection(members_with_refs):
loaded_containers.append(obj_set)
return loaded_containers

View file

@ -1,4 +1,4 @@
from avalon import api, style
from avalon import api
from openpype.api import Logger
from openpype.hosts.nuke.api.lib import set_avalon_knob_data
@ -7,7 +7,7 @@ class RepairOldLoaders(api.InventoryAction):
label = "Repair Old Loaders"
icon = "gears"
color = style.colors.alert
color = "#cc0000"
log = Logger.get_logger(__name__)

View file

@ -1,4 +1,4 @@
from avalon import api, style, io
from avalon import api, io
import nuke
import nukescripts
@ -23,7 +23,7 @@ class LoadBackdropNodes(api.Loader):
label = "Iport Nuke Nodes"
order = 0
icon = "eye"
color = style.colors.light
color = "white"
node_color = "0x7533c1ff"
def load(self, context, name, namespace, data):

View file

@ -1,7 +1,8 @@
import json
from collections import OrderedDict
import nuke
from avalon import api, style, io
from avalon import api, io
from openpype.hosts.nuke.api import (
containerise,
update_container,
@ -18,7 +19,7 @@ class LoadEffects(api.Loader):
label = "Load Effects - nodes"
order = 0
icon = "cc"
color = style.colors.light
color = "white"
ignore_attr = ["useLifetime"]

View file

@ -3,7 +3,8 @@ from collections import OrderedDict
import nuke
from avalon import api, style, io
from avalon import api, io
from openpype.hosts.nuke.api import lib
from openpype.hosts.nuke.api import (
containerise,
@ -21,7 +22,7 @@ class LoadEffectsInputProcess(api.Loader):
label = "Load Effects - Input Process"
order = 0
icon = "eye"
color = style.colors.alert
color = "#cc0000"
ignore_attr = ["useLifetime"]
def load(self, context, name, namespace, data):

View file

@ -1,5 +1,6 @@
import nuke
from avalon import api, style, io
from avalon import api, io
from openpype.hosts.nuke.api.lib import (
maintained_selection,
get_avalon_knob_data,
@ -21,7 +22,7 @@ class LoadGizmo(api.Loader):
label = "Load Gizmo"
order = 0
icon = "dropbox"
color = style.colors.light
color = "white"
node_color = "0x75338eff"
def load(self, context, name, namespace, data):

View file

@ -1,5 +1,6 @@
from avalon import api, style, io
from avalon import api, io
import nuke
from openpype.hosts.nuke.api.lib import (
maintained_selection,
create_backdrop,
@ -22,7 +23,7 @@ class LoadGizmoInputProcess(api.Loader):
label = "Load Gizmo - Input Process"
order = 0
icon = "eye"
color = style.colors.alert
color = "#cc0000"
node_color = "0x7533c1ff"
def load(self, context, name, namespace, data):

View file

@ -1,5 +1,6 @@
import nuke
from avalon import api, style, io
from avalon import api, io
from openpype.hosts.nuke.api.lib import get_avalon_knob_data
from openpype.hosts.nuke.api import (
containerise,
@ -17,7 +18,7 @@ class LinkAsGroup(api.Loader):
label = "Load Precomp"
order = 0
icon = "file"
color = style.colors.alert
color = "#cc0000"
def load(self, context, name, namespace, data):
# for k, v in context.items():

View file

@ -1594,11 +1594,13 @@ def get_creator_by_name(creator_name, case_sensitive=False):
Returns:
Creator: Return first matching plugin or `None`.
"""
from openpype.pipeline import LegacyCreator
# Lower input creator name if is not case sensitive
if not case_sensitive:
creator_name = creator_name.lower()
for creator_plugin in avalon.api.discover(avalon.api.Creator):
for creator_plugin in avalon.api.discover(LegacyCreator):
_creator_name = creator_plugin.__name__
# Lower creator plugin name if is not case sensitive

View file

@ -1,4 +1,5 @@
from avalon import api, style
from avalon import api
from openpype.style import get_default_entity_icon_color
class CopyFile(api.Loader):
@ -10,7 +11,7 @@ class CopyFile(api.Loader):
label = "Copy File"
order = 10
icon = "copy"
color = style.colors.default
color = get_default_entity_icon_color()
def load(self, context, name=None, namespace=None, data=None):
self.log.info("Added copy to clipboard: {0}".format(self.fname))

View file

@ -8,9 +8,10 @@ import ftrack_api
import qargparse
from Qt import QtWidgets, QtCore
from avalon import api, style
from avalon import api
from avalon.api import AvalonMongoDB
import avalon.pipeline
from openpype import style
from openpype.api import Anatomy

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<path d="M5 50A45 45 0 0 0 95 50A45 47 0 0 1 5 50" fill="#6c6c6c" stroke="none" transform="rotate(312.01 50 51)">
<animateTransform attributeName="transform" type="rotate" dur="0.47846889952153115s" repeatCount="indefinite" keyTimes="0;1" values="0 50 51;360 50 51"></animateTransform>
</path>
<!-- [ldio] generated by https://loading.io/ --></svg>

After

Width:  |  Height:  |  Size: 635 B

View file

@ -7,13 +7,19 @@ from openpype import resources
from .color_defs import parse_color
_STYLESHEET_CACHE = None
_FONT_IDS = None
current_dir = os.path.dirname(os.path.abspath(__file__))
class _Cache:
stylesheet = None
font_ids = None
tools_icon_color = None
default_entity_icon_color = None
disabled_entity_icon_color = None
deprecated_entity_font_color = None
def get_style_image_path(image_name):
# All filenames are lowered
image_name = image_name.lower()
@ -125,21 +131,19 @@ def _load_font():
"""Load and register fonts into Qt application."""
from Qt import QtGui
global _FONT_IDS
# Check if font ids are still loaded
if _FONT_IDS is not None:
for font_id in tuple(_FONT_IDS):
if _Cache.font_ids is not None:
for font_id in tuple(_Cache.font_ids):
font_families = QtGui.QFontDatabase.applicationFontFamilies(
font_id
)
# Reset font if font id is not available
if not font_families:
_FONT_IDS = None
_Cache.font_ids = None
break
if _FONT_IDS is None:
_FONT_IDS = []
if _Cache.font_ids is None:
_Cache.font_ids = []
fonts_dirpath = os.path.join(current_dir, "fonts")
font_dirs = []
font_dirs.append(os.path.join(fonts_dirpath, "Noto_Sans"))
@ -157,7 +161,7 @@ def _load_font():
continue
full_path = os.path.join(font_dir, filename)
font_id = QtGui.QFontDatabase.addApplicationFont(full_path)
_FONT_IDS.append(font_id)
_Cache.font_ids.append(font_id)
font_families = QtGui.QFontDatabase.applicationFontFamilies(
font_id
)
@ -167,11 +171,11 @@ def _load_font():
def load_stylesheet():
"""Load and return OpenPype Qt stylesheet."""
global _STYLESHEET_CACHE
if _STYLESHEET_CACHE is None:
_STYLESHEET_CACHE = _load_stylesheet()
if _Cache.stylesheet is None:
_Cache.stylesheet = _load_stylesheet()
_load_font()
return _STYLESHEET_CACHE
return _Cache.stylesheet
def get_app_icon_path():
@ -182,3 +186,63 @@ def get_app_icon_path():
def app_icon_path():
# Backwards compatibility
return get_app_icon_path()
def get_default_tools_icon_color():
"""Default color used in tool icons.
Color must be possible to parse using QColor.
Returns:
str: Color as a string.
"""
if _Cache.tools_icon_color is None:
color_data = get_colors_data()
_Cache.tools_icon_color = color_data["icon-tools"]
return _Cache.tools_icon_color
def get_default_entity_icon_color():
"""Default color of entities icons.
Color must be possible to parse using QColor.
Returns:
str: Color as a string.
"""
if _Cache.default_entity_icon_color is None:
color_data = get_colors_data()
_Cache.default_entity_icon_color = color_data["icon-entity-default"]
return _Cache.default_entity_icon_color
def get_disabled_entity_icon_color():
"""Default color of entities icons.
TODO: Find more suitable function name.
Color must be possible to parse using QColor.
Returns:
str: Color as a string.
"""
if _Cache.disabled_entity_icon_color is None:
color_data = get_colors_data()
_Cache.disabled_entity_icon_color = color_data["icon-entity-disabled"]
return _Cache.disabled_entity_icon_color
def get_deprecated_entity_font_color():
"""Font color for deprecated entities.
Color must be possible to parse using QColor.
Returns:
str: Color as a string.
"""
if _Cache.deprecated_entity_font_color is None:
color_data = get_colors_data()
_Cache.deprecated_entity_font_color = (
color_data["font-entity-deprecated"]
)
return _Cache.deprecated_entity_font_color

View file

@ -56,6 +56,12 @@
"delete-btn-bg": "rgb(201, 54, 54)",
"delete-btn-bg-disabled": "rgba(201, 54, 54, 64)",
"icon-tools": "#ffffff",
"icon-alert-tools": "#AA5050",
"icon-entity-default": "#bfccd6",
"icon-entity-disabled": "#808080",
"font-entity-deprecated": "#666666",
"tab-widget": {
"bg": "#21252B",
"bg-selected": "#434a56",

View file

@ -14,7 +14,10 @@ from openpype.lib.applications import (
CUSTOM_LAUNCH_APP_GROUPS,
ApplicationManager
)
from openpype.tools.utils.lib import DynamicQThread
from openpype.tools.utils.lib import (
DynamicQThread,
get_project_icon,
)
from openpype.tools.utils.assets_widget import (
AssetModel,
ASSET_NAME_ROLE
@ -400,6 +403,7 @@ class LauncherModel(QtCore.QObject):
self._dbcon = dbcon
# Available project names
self._project_names = set()
self._project_docs_by_name = {}
# Context data
self._asset_docs = []
@ -460,6 +464,9 @@ class LauncherModel(QtCore.QObject):
"""Available project names."""
return self._project_names
def get_project_doc(self, project_name):
return self._project_docs_by_name.get(project_name)
@property
def asset_filter_data_by_id(self):
"""Prepared filter data by asset id."""
@ -516,9 +523,13 @@ class LauncherModel(QtCore.QObject):
"""Refresh projects."""
current_project = self.project_name
project_names = set()
project_docs_by_name = {}
for project_doc in self._dbcon.projects(only_active=True):
project_names.add(project_doc["name"])
project_name = project_doc["name"]
project_names.add(project_name)
project_docs_by_name[project_name] = project_doc
self._project_docs_by_name = project_docs_by_name
self._project_names = project_names
self.projects_refreshed.emit()
if (
@ -694,6 +705,11 @@ class LauncherTaskModel(TasksModel):
self._launcher_model = launcher_model
super(LauncherTaskModel, self).__init__(*args, **kwargs)
def _refresh_project_doc(self):
self._project_doc = self._launcher_model.get_project_doc(
self._launcher_model.project_name
)
def set_asset_id(self, asset_id):
asset_doc = None
if self._context_is_valid():
@ -718,7 +734,6 @@ class AssetRecursiveSortFilterModel(QtCore.QSortFilterProxyModel):
self._assignee_filter = self._launcher_model.assignee_filters
self.invalidateFilter()
"""Filters to the regex if any of the children matches allow parent"""
def filterAcceptsRow(self, row, parent):
if (
not self._name_filter
@ -818,7 +833,6 @@ class ProjectModel(QtGui.QStandardItemModel):
super(ProjectModel, self).__init__(parent=parent)
self._launcher_model = launcher_model
self.project_icon = qtawesome.icon("fa.map", color="white")
self._project_names = set()
launcher_model.projects_refreshed.connect(self._on_refresh)
@ -863,7 +877,11 @@ class ProjectModel(QtGui.QStandardItemModel):
for row in reversed(sorted(row_counts.keys())):
items = []
for project_name in row_counts[row]:
item = QtGui.QStandardItem(self.project_icon, project_name)
project_doc = self._launcher_model.get_project_doc(
project_name
)
icon = get_project_icon(project_doc)
item = QtGui.QStandardItem(icon, project_name)
items.append(item)
self.invisibleRootItem().insertRows(row, items)

View file

@ -3,15 +3,13 @@ import re
import math
from uuid import uuid4
from avalon import (
style,
schema
)
from Qt import QtCore, QtGui
import qtawesome
from avalon import schema
from avalon.lib import HeroVersionType
from openpype.style import get_default_entity_icon_color
from openpype.tools.utils.models import TreeModel, Item
from openpype.tools.utils import lib
@ -180,7 +178,10 @@ class SubsetsModel(TreeModel, BaseRepresentationModel):
self._sorter = None
self._grouping = grouping
self._icons = {
"subset": qtawesome.icon("fa.file-o", color=style.colors.default)
"subset": qtawesome.icon(
"fa.file-o",
color=get_default_entity_icon_color()
)
}
self._items_by_id = {}
@ -1066,8 +1067,10 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
self._docs = {}
self._icons = lib.get_repre_icons()
self._icons["repre"] = qtawesome.icon("fa.file-o",
color=style.colors.default)
self._icons["repre"] = qtawesome.icon(
"fa.file-o",
color=get_default_entity_icon_color()
)
self._items_by_id = {}
def set_version_ids(self, version_ids):
@ -1165,7 +1168,7 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
"remote_site_name": self.remote_site,
"icon": qtawesome.icon(
"fa.folder",
color=style.colors.default
color=get_default_entity_icon_color()
)
})
self._items_by_id[item_id] = group_item

View file

@ -1,9 +1,9 @@
from .app import (
App,
MayaLookAssignerWindow,
show
)
__all__ = [
"App",
"MayaLookAssignerWindow",
"show"]

View file

@ -4,10 +4,10 @@ import logging
from Qt import QtWidgets, QtCore
from openpype.hosts.maya.api.lib import assign_look_by_version
from avalon import style, io
from avalon import io
from openpype import style
from openpype.tools.utils.lib import qt_app_context
from openpype.hosts.maya.api.lib import assign_look_by_version
from maya import cmds
# old api for MFileIO
@ -28,10 +28,10 @@ module = sys.modules[__name__]
module.window = None
class App(QtWidgets.QWidget):
class MayaLookAssignerWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent=parent)
super(MayaLookAssignerWindow, self).__init__(parent=parent)
self.log = logging.getLogger(__name__)
@ -56,30 +56,41 @@ class App(QtWidgets.QWidget):
def setup_ui(self):
"""Build the UI"""
main_splitter = QtWidgets.QSplitter(self)
# Assets (left)
asset_outliner = AssetOutliner()
asset_outliner = AssetOutliner(main_splitter)
# Looks (right)
looks_widget = QtWidgets.QWidget()
looks_layout = QtWidgets.QVBoxLayout(looks_widget)
looks_widget = QtWidgets.QWidget(main_splitter)
look_outliner = LookOutliner() # Database look overview
look_outliner = LookOutliner(looks_widget) # Database look overview
assign_selected = QtWidgets.QCheckBox("Assign to selected only")
assign_selected = QtWidgets.QCheckBox(
"Assign to selected only", looks_widget
)
assign_selected.setToolTip("Whether to assign only to selected nodes "
"or to the full asset")
remove_unused_btn = QtWidgets.QPushButton("Remove Unused Looks")
remove_unused_btn = QtWidgets.QPushButton(
"Remove Unused Looks", looks_widget
)
looks_layout = QtWidgets.QVBoxLayout(looks_widget)
looks_layout.addWidget(look_outliner)
looks_layout.addWidget(assign_selected)
looks_layout.addWidget(remove_unused_btn)
main_splitter.addWidget(asset_outliner)
main_splitter.addWidget(looks_widget)
main_splitter.setSizes([350, 200])
# Footer
status = QtWidgets.QStatusBar()
status = QtWidgets.QStatusBar(self)
status.setSizeGripEnabled(False)
status.setFixedHeight(25)
warn_layer = QtWidgets.QLabel("Current Layer is not "
"defaultRenderLayer")
warn_layer = QtWidgets.QLabel(
"Current Layer is not defaultRenderLayer", self
)
warn_layer.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
warn_layer.setStyleSheet("color: #DD5555; font-weight: bold;")
warn_layer.setFixedHeight(25)
@ -92,11 +103,6 @@ class App(QtWidgets.QWidget):
# Build up widgets
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.setSpacing(0)
main_splitter = QtWidgets.QSplitter()
main_splitter.setStyleSheet("QSplitter{ border: 0px; }")
main_splitter.addWidget(asset_outliner)
main_splitter.addWidget(looks_widget)
main_splitter.setSizes([350, 200])
main_layout.addWidget(main_splitter)
main_layout.addLayout(footer)
@ -124,6 +130,8 @@ class App(QtWidgets.QWidget):
self.remove_unused = remove_unused_btn
self.assign_selected = assign_selected
self._first_show = True
def setup_connections(self):
"""Connect interactive widgets with actions"""
if self._connections_set_up:
@ -147,11 +155,14 @@ class App(QtWidgets.QWidget):
def showEvent(self, event):
self.setup_connections()
super(App, self).showEvent(event)
super(MayaLookAssignerWindow, self).showEvent(event)
if self._first_show:
self._first_show = False
self.setStyleSheet(style.load_stylesheet())
def closeEvent(self, event):
self.remove_connection()
super(App, self).closeEvent(event)
super(MayaLookAssignerWindow, self).closeEvent(event)
def _on_renderlayer_switch(self, *args):
"""Callback that updates on Maya renderlayer switch"""
@ -267,8 +278,7 @@ def show():
if widget.objectName() == "MayaWindow")
with qt_app_context():
window = App(parent=mainwindow)
window.setStyleSheet(style.load_stylesheet())
window = MayaLookAssignerWindow(parent=mainwindow)
window.show()
module.window = window

View file

@ -3,14 +3,19 @@ from collections import defaultdict
from Qt import QtCore
import qtawesome
from avalon.style import colors
from openpype.tools.utils import models
from openpype.style import get_default_entity_icon_color
class AssetModel(models.TreeModel):
Columns = ["label"]
def __init__(self, *args, **kwargs):
super(AssetModel, self).__init__(*args, **kwargs)
self._icon_color = get_default_entity_icon_color()
def add_items(self, items):
"""
Add items to model with needed data
@ -65,8 +70,10 @@ class AssetModel(models.TreeModel):
node = index.internalPointer()
icon = node.get("icon")
if icon:
return qtawesome.icon("fa.{0}".format(icon),
color=colors.default)
return qtawesome.icon(
"fa.{0}".format(icon),
color=self._icon_color
)
return super(AssetModel, self).data(index, role)

View file

@ -1,9 +1,6 @@
from Qt import QtWidgets, QtCore
DEFAULT_COLOR = "#fb9c15"
class View(QtWidgets.QTreeView):
data_changed = QtCore.Signal()

View file

@ -14,7 +14,7 @@ from .models import (
LookModel
)
from . import commands
from . import views
from .views import View
from maya import cmds
@ -24,25 +24,28 @@ class AssetOutliner(QtWidgets.QWidget):
selection_changed = QtCore.Signal()
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
super(AssetOutliner, self).__init__(parent)
layout = QtWidgets.QVBoxLayout()
title = QtWidgets.QLabel("Assets")
title = QtWidgets.QLabel("Assets", self)
title.setAlignment(QtCore.Qt.AlignCenter)
title.setStyleSheet("font-weight: bold; font-size: 12px")
model = AssetModel()
view = views.View()
view = View(self)
view.setModel(model)
view.customContextMenuRequested.connect(self.right_mouse_menu)
view.setSortingEnabled(False)
view.setHeaderHidden(True)
view.setIndentation(10)
from_all_asset_btn = QtWidgets.QPushButton("Get All Assets")
from_selection_btn = QtWidgets.QPushButton("Get Assets From Selection")
from_all_asset_btn = QtWidgets.QPushButton(
"Get All Assets", self
)
from_selection_btn = QtWidgets.QPushButton(
"Get Assets From Selection", self
)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(title)
layout.addWidget(from_all_asset_btn)
layout.addWidget(from_selection_btn)
@ -58,8 +61,6 @@ class AssetOutliner(QtWidgets.QWidget):
self.view = view
self.model = model
self.setLayout(layout)
self.log = logging.getLogger(__name__)
def clear(self):
@ -188,15 +189,10 @@ class LookOutliner(QtWidgets.QWidget):
menu_apply_action = QtCore.Signal()
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
# look manager layout
layout = QtWidgets.QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(10)
super(LookOutliner, self).__init__(parent)
# Looks from database
title = QtWidgets.QLabel("Looks")
title = QtWidgets.QLabel("Looks", self)
title.setAlignment(QtCore.Qt.AlignCenter)
title.setStyleSheet("font-weight: bold; font-size: 12px")
title.setAlignment(QtCore.Qt.AlignCenter)
@ -207,13 +203,17 @@ class LookOutliner(QtWidgets.QWidget):
proxy = QtCore.QSortFilterProxyModel()
proxy.setSourceModel(model)
view = views.View()
view = View(self)
view.setModel(proxy)
view.setMinimumHeight(180)
view.setToolTip("Use right mouse button menu for direct actions")
view.customContextMenuRequested.connect(self.right_mouse_menu)
view.sortByColumn(0, QtCore.Qt.AscendingOrder)
# look manager layout
layout = QtWidgets.QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(10)
layout.addWidget(title)
layout.addWidget(view)

View file

@ -1,4 +1,4 @@
from Qt import QtCore, QtGui, QtWidgets
from Qt import QtCore, QtWidgets
class ComboItemDelegate(QtWidgets.QStyledItemDelegate):

View file

@ -1,7 +1,7 @@
from Qt import QtCore, QtGui
from openpype.tools.utils.tasks_widget import TasksWidget, TASK_NAME_ROLE
from openpype.tools.utils.lib import get_task_icon
from openpype.tools.utils.lib import get_default_task_icon
class TasksModel(QtGui.QStandardItemModel):
@ -120,7 +120,7 @@ class TasksModel(QtGui.QStandardItemModel):
item = QtGui.QStandardItem(task_name)
item.setData(task_name, TASK_NAME_ROLE)
if task_name:
item.setData(get_task_icon(), QtCore.Qt.DecorationRole)
item.setData(get_default_task_icon(), QtCore.Qt.DecorationRole)
self._items_by_name[task_name] = item
new_items.append(item)

View file

@ -6,8 +6,9 @@ from collections import defaultdict
from Qt import QtCore, QtGui
import qtawesome
from avalon import api, io, style, schema
from avalon import api, io, schema
from avalon.lib import HeroVersionType
from openpype.style import get_default_entity_icon_color
from openpype.tools.utils.models import TreeModel, Item
from .lib import (
@ -38,6 +39,8 @@ class InventoryModel(TreeModel):
self._hierarchy_view = False
self._default_icon_color = get_default_entity_icon_color()
manager = ModulesManager()
sync_server = manager.modules_by_name["sync_server"]
self.sync_enabled = sync_server.enabled
@ -131,7 +134,7 @@ class InventoryModel(TreeModel):
if role == QtCore.Qt.DecorationRole:
if index.column() == 0:
# Override color
color = item.get("color", style.colors.default)
color = item.get("color", self._default_icon_color)
if item.get("isGroupNode"): # group-item
return qtawesome.icon("fa.folder", color=color)
if item.get("isNotSet"):

View file

@ -5,9 +5,10 @@ from functools import partial
from Qt import QtWidgets, QtCore
import qtawesome
from avalon import io, api, style
from avalon import io, api
from avalon.lib import HeroVersionType
from openpype import style
from openpype.modules import ModulesManager
from openpype.tools.utils.lib import (
get_progress_for_repre,

View file

@ -1,10 +1,15 @@
import logging
import collections
from Qt import QtCore, QtGui
import qtawesome
from . import TreeModel, Node
from avalon import style
from openpype.style import (
get_default_entity_icon_color,
get_deprecated_entity_font_color,
)
from . import TreeModel, Node
log = logging.getLogger(__name__)
@ -49,6 +54,14 @@ class AssetModel(TreeModel):
def __init__(self, dbcon, parent=None):
super(AssetModel, self).__init__(parent=parent)
self.dbcon = dbcon
self._default_asset_icon_color = QtGui.QColor(
get_default_entity_icon_color()
)
self._deprecated_asset_font_color = QtGui.QColor(
get_deprecated_entity_font_color()
)
self.refresh()
def _add_hierarchy(self, assets, parent=None, silos=None):
@ -163,7 +176,7 @@ class AssetModel(TreeModel):
icon = data.get("icon", None)
if icon is None and node.get("type") == "silo":
icon = "database"
color = data.get("color", style.colors.default)
color = data.get("color", self._default_asset_icon_color)
if icon is None:
# Use default icons if no custom one is specified.
@ -189,7 +202,7 @@ class AssetModel(TreeModel):
if role == QtCore.Qt.ForegroundRole: # font color
if "deprecated" in node.get("tags", []):
return QtGui.QColor(style.colors.light).darker(250)
return QtGui.QColor(self._deprecated_asset_font_color)
if role == self.ObjectIdRole:
return node.get("_id", None)

View file

@ -1,7 +1,9 @@
from Qt import QtCore
import qtawesome
from openpype.style import get_default_entity_icon_color
from . import Node, TreeModel
from avalon import style
class TasksTemplateModel(TreeModel):
@ -14,7 +16,7 @@ class TasksTemplateModel(TreeModel):
self.selectable = selectable
self.icon = qtawesome.icon(
'fa.calendar-check-o',
color=style.colors.default
color=get_default_entity_icon_color()
)
def set_tasks(self, tasks):

View file

@ -4,7 +4,7 @@ import qtawesome
from openpype.tools.utils import PlaceholderLineEdit
from avalon import style
from openpype.style import get_default_tools_icon_color
from . import RecursiveSortFilterProxyModel, AssetModel
from . import TasksTemplateModel, DeselectableTreeView
@ -165,7 +165,9 @@ class AssetWidget(QtWidgets.QWidget):
# Header
header = QtWidgets.QHBoxLayout()
icon = qtawesome.icon("fa.refresh", color=style.colors.light)
icon = qtawesome.icon(
"fa.refresh", color=get_default_tools_icon_color()
)
refresh = QtWidgets.QPushButton(icon, "")
refresh.setToolTip("Refresh items")

View file

@ -42,6 +42,7 @@ __all__ = (
"set_style_property",
"DynamicQThread",
"qt_app_context",
"get_asset_icon",
"RecursiveSortFilterProxyModel",
)

View file

@ -5,9 +5,10 @@ import Qt
from Qt import QtWidgets, QtCore, QtGui
import qtawesome
from avalon import style
from openpype.style import get_objected_colors
from openpype.style import (
get_objected_colors,
get_default_tools_icon_color,
)
from openpype.tools.flickcharm import FlickCharm
from .views import (
@ -512,7 +513,7 @@ class AssetModel(QtGui.QStandardItemModel):
item.setData(asset_label, ASSET_LABEL_ROLE)
has_children = item.rowCount() > 0
icon = get_asset_icon(asset_data, has_children)
icon = get_asset_icon(asset_doc, has_children)
item.setData(icon, QtCore.Qt.DecorationRole)
def _threaded_fetch(self):
@ -589,7 +590,7 @@ class AssetsWidget(QtWidgets.QWidget):
view.setModel(proxy)
current_asset_icon = qtawesome.icon(
"fa.arrow-down", color=style.colors.light
"fa.arrow-down", color=get_default_tools_icon_color()
)
current_asset_btn = QtWidgets.QPushButton(self)
current_asset_btn.setIcon(current_asset_icon)
@ -597,7 +598,9 @@ class AssetsWidget(QtWidgets.QWidget):
# Hide by default
current_asset_btn.setVisible(False)
refresh_icon = qtawesome.icon("fa.refresh", color=style.colors.light)
refresh_icon = qtawesome.icon(
"fa.refresh", color=get_default_tools_icon_color()
)
refresh_btn = QtWidgets.QPushButton(self)
refresh_btn.setIcon(refresh_icon)
refresh_btn.setToolTip("Refresh items")

View file

@ -224,20 +224,18 @@ class HostToolsHelper:
def get_look_assigner_tool(self, parent):
"""Create, cache and return look assigner tool window."""
if self._look_assigner_tool is None:
import mayalookassigner
from openpype.tools.mayalookassigner import MayaLookAssignerWindow
mayalookassigner_window = mayalookassigner.App(parent)
mayalookassigner_window = MayaLookAssignerWindow(parent)
self._look_assigner_tool = mayalookassigner_window
return self._look_assigner_tool
def show_look_assigner(self, parent=None):
"""Look manager is Maya specific tool for look management."""
from avalon import style
with qt_app_context():
look_assigner_tool = self.get_look_assigner_tool(parent)
look_assigner_tool.show()
look_assigner_tool.setStyleSheet(style.load_stylesheet())
def get_experimental_tools_dialog(self, parent=None):
"""Dialog of experimental tools.

View file

@ -7,8 +7,8 @@ from Qt import QtWidgets, QtCore, QtGui
import qtawesome
import avalon.api
from avalon import style
from openpype.style import get_default_entity_icon_color
from openpype.api import (
get_project_settings,
Logger
@ -92,10 +92,6 @@ def qt_app_context():
yield app
# Backwards compatibility
application = qt_app_context
class SharedObjects:
jobs = {}
icons = {}
@ -126,30 +122,74 @@ def get_qta_icon_by_name_and_color(icon_name, icon_color):
return icon
def get_project_icon(project_doc):
if project_doc:
icon_name = project_doc.get("data", {}).get("icon")
icon = get_qta_icon_by_name_and_color(icon_name, "white")
if icon:
return icon
return get_qta_icon_by_name_and_color(
"fa.map", get_default_entity_icon_color()
)
def get_asset_icon_name(asset_doc, has_children=True):
icon_name = asset_doc["data"].get("icon")
if icon_name:
return icon_name
if has_children:
return "folder"
return "folder-o"
def get_asset_icon_color(asset_doc):
icon_color = asset_doc["data"].get("color")
if icon_color:
return icon_color
return get_default_entity_icon_color()
def get_asset_icon(asset_doc, has_children=False):
asset_data = asset_doc.get("data") or {}
icon_color = asset_data.get("color") or style.colors.default
icon_name = asset_data.get("icon")
if not icon_name:
# Use default icons if no custom one is specified.
# If it has children show a full folder, otherwise
# show an open folder
if has_children:
icon_name = "folder"
else:
icon_name = "folder-o"
icon_name = get_asset_icon_name(asset_doc, has_children)
icon_color = get_asset_icon_color(asset_doc)
return get_qta_icon_by_name_and_color(icon_name, icon_color)
def get_task_icon():
"""Get icon for a task.
def get_default_task_icon(color=None):
if color is None:
color = get_default_entity_icon_color()
return get_qta_icon_by_name_and_color("fa.male", color)
TODO: Get task icon based on data in database.
def get_task_icon(project_doc, asset_doc, task_name):
"""Get icon for a task.
Icon should be defined by task type which is stored on project.
"""
return get_qta_icon_by_name_and_color("fa.male", style.colors.default)
color = get_default_entity_icon_color()
tasks_info = asset_doc.get("data", {}).get("tasks") or {}
task_info = tasks_info.get(task_name) or {}
task_icon = task_info.get("icon")
if task_icon:
icon = get_qta_icon_by_name_and_color(task_icon, color)
if icon is not None:
return icon
task_type = task_info.get("type")
task_types = project_doc["config"]["tasks"]
task_type_info = task_types.get(task_type) or {}
task_type_icon = task_type_info.get("icon")
if task_type_icon:
icon = get_qta_icon_by_name_and_color(task_icon, color)
if icon is not None:
return icon
return get_default_task_icon(color)
def schedule(func, time, channel="default"):
@ -412,6 +452,7 @@ class GroupsConfig:
def __init__(self, dbcon):
self.dbcon = dbcon
self.groups = {}
self._default_group_color = get_default_entity_icon_color()
@classmethod
def default_group_config(cls):
@ -419,7 +460,7 @@ class GroupsConfig:
cls._default_group_config = {
"icon": qtawesome.icon(
"fa.object-group",
color=style.colors.default
color=get_default_entity_icon_color()
),
"order": 0
}
@ -453,7 +494,7 @@ class GroupsConfig:
for config in group_configs:
name = config["name"]
icon = "fa." + config.get("icon", "object-group")
color = config.get("color", style.colors.default)
color = config.get("color", self._default_group_color)
order = float(config.get("order", 0))
self.groups[name] = {

View file

@ -1,7 +1,8 @@
from Qt import QtWidgets, QtCore, QtGui
import qtawesome
from avalon import style
from openpype.style import get_disabled_entity_icon_color
from openpype.tools.utils.lib import get_task_icon
from .views import DeselectableTreeView
@ -21,53 +22,35 @@ class TasksModel(QtGui.QStandardItemModel):
self.setHeaderData(
0, QtCore.Qt.Horizontal, "Tasks", QtCore.Qt.DisplayRole
)
self._default_icon = qtawesome.icon(
"fa.male",
color=style.colors.default
)
self._no_tasks_icon = qtawesome.icon(
"fa.exclamation-circle",
color=style.colors.mid
color=get_disabled_entity_icon_color()
)
self._cached_icons = {}
self._project_task_types = {}
self._project_doc = {}
self._empty_tasks_item = None
self._last_asset_id = None
self._loaded_project_name = None
def _context_is_valid(self):
if self.dbcon.Session.get("AVALON_PROJECT"):
if self._get_current_project():
return True
return False
def refresh(self):
self._refresh_task_types()
self._refresh_project_doc()
self.set_asset_id(self._last_asset_id)
def _refresh_task_types(self):
def _refresh_project_doc(self):
# Get the project configured icons from database
task_types = {}
project_doc = {}
if self._context_is_valid():
project = self.dbcon.find_one(
{"type": "project"},
{"config.tasks"}
)
task_types = project["config"].get("tasks") or task_types
self._project_task_types = task_types
project_doc = self.dbcon.find_one({"type": "project"})
def _try_get_awesome_icon(self, icon_name):
icon = None
if icon_name:
try:
icon = qtawesome.icon(
"fa.{}".format(icon_name),
color=style.colors.default
)
except Exception:
pass
return icon
self._loaded_project_name = self._get_current_project()
self._project_doc = project_doc
def headerData(self, section, orientation, role=None):
if role is None:
@ -82,28 +65,8 @@ class TasksModel(QtGui.QStandardItemModel):
return super(TasksModel, self).headerData(section, orientation, role)
def _get_icon(self, task_icon, task_type_icon):
if task_icon in self._cached_icons:
return self._cached_icons[task_icon]
icon = self._try_get_awesome_icon(task_icon)
if icon is not None:
self._cached_icons[task_icon] = icon
return icon
if task_type_icon in self._cached_icons:
icon = self._cached_icons[task_type_icon]
self._cached_icons[task_icon] = icon
return icon
icon = self._try_get_awesome_icon(task_type_icon)
if icon is None:
icon = self._default_icon
self._cached_icons[task_icon] = icon
self._cached_icons[task_type_icon] = icon
return icon
def _get_current_project(self):
return self.dbcon.Session.get("AVALON_PROJECT")
def set_asset_id(self, asset_id):
asset_doc = None
@ -128,6 +91,9 @@ class TasksModel(QtGui.QStandardItemModel):
Arguments:
asset_doc (dict): Asset document from MongoDB.
"""
if self._loaded_project_name != self._get_current_project():
self._refresh_project_doc()
asset_tasks = {}
self._last_asset_id = None
if asset_doc:
@ -138,13 +104,11 @@ class TasksModel(QtGui.QStandardItemModel):
root_item.removeRows(0, root_item.rowCount())
items = []
for task_name, task_info in asset_tasks.items():
task_icon = task_info.get("icon")
task_type = task_info.get("type")
task_order = task_info.get("order")
task_type_info = self._project_task_types.get(task_type) or {}
task_type_icon = task_type_info.get("icon")
icon = self._get_icon(task_icon, task_type_icon)
icon = get_task_icon(self._project_doc, asset_doc, task_name)
task_assignees = set()
assignees_data = task_info.get("assignees") or []

View file

@ -1,5 +1,5 @@
import os
from avalon import style
from openpype.resources import get_image_path
from Qt import QtWidgets, QtCore, QtGui, QtSvg
@ -24,11 +24,8 @@ class TreeViewSpinner(QtWidgets.QTreeView):
def __init__(self, parent=None):
super(TreeViewSpinner, self).__init__(parent=parent)
loading_image_path = os.path.join(
os.path.dirname(os.path.abspath(style.__file__)),
"svg",
"spinner-200.svg"
)
loading_image_path = get_image_path("spinner-200.svg")
self.spinner = QtSvg.QSvgRenderer(loading_image_path)
self.is_loading = False

View file

@ -4,7 +4,11 @@ import logging
from Qt import QtCore
import qtawesome
from avalon import style
from openpype.style import (
get_default_entity_icon_color,
get_disabled_entity_icon_color,
)
from openpype.tools.utils.models import TreeModel, Item
log = logging.getLogger(__name__)
@ -25,7 +29,10 @@ class FilesModel(TreeModel):
self._root = None
self._file_extensions = file_extensions
self._icons = {
"file": qtawesome.icon("fa.file-o", color=style.colors.default)
"file": qtawesome.icon(
"fa.file-o",
color=get_default_entity_icon_color()
)
}
def set_root(self, root):
@ -64,7 +71,10 @@ class FilesModel(TreeModel):
"date": None,
"filepath": None,
"enabled": False,
"icon": qtawesome.icon("fa.times", color=style.colors.mid)
"icon": qtawesome.icon(
"fa.times",
color=get_disabled_entity_icon_color()
)
})
self.add_child(item)
self.endResetModel()