diff --git a/client/ayon_core/cli.py b/client/ayon_core/cli.py
index d7cd3ba7f5..6f89a6d17d 100644
--- a/client/ayon_core/cli.py
+++ b/client/ayon_core/cli.py
@@ -252,7 +252,6 @@ def _set_global_environments() -> None:
os.environ.update(env)
# Hardcoded default values
- os.environ["PYBLISH_GUI"] = "pyblish_pype"
# Change scale factor only if is not set
if "QT_AUTO_SCREEN_SCALE_FACTOR" not in os.environ:
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
@@ -290,8 +289,6 @@ def main(*args, **kwargs):
split_paths = python_path.split(os.pathsep)
additional_paths = [
- # add AYON tools for 'pyblish_pype'
- os.path.join(AYON_CORE_ROOT, "tools"),
# add common AYON vendor
# (common for multiple Python interpreter versions)
os.path.join(AYON_CORE_ROOT, "vendor", "python")
diff --git a/client/ayon_core/tools/pyblish_pype/__init__.py b/client/ayon_core/tools/pyblish_pype/__init__.py
deleted file mode 100644
index ef507005a5..0000000000
--- a/client/ayon_core/tools/pyblish_pype/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from .version import version, version_info, __version__
-
-# This must be run prior to importing the application, due to the
-# application requiring a discovered copy of Qt bindings.
-
-from .app import show
-
-__all__ = [
- 'show',
- 'version',
- 'version_info',
- '__version__'
-]
diff --git a/client/ayon_core/tools/pyblish_pype/__main__.py b/client/ayon_core/tools/pyblish_pype/__main__.py
deleted file mode 100644
index 5fc1b44a35..0000000000
--- a/client/ayon_core/tools/pyblish_pype/__main__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from .app import show
-
-
-if __name__ == '__main__':
- import argparse
-
- parser = argparse.ArgumentParser()
- parser.add_argument("--debug", action="store_true")
-
- args = parser.parse_args()
-
- if args.debug:
- from . import mock
- import pyblish.api
-
- for Plugin in mock.plugins:
- pyblish.api.register_plugin(Plugin)
-
- show()
diff --git a/client/ayon_core/tools/pyblish_pype/app.css b/client/ayon_core/tools/pyblish_pype/app.css
deleted file mode 100644
index 33b6acbddb..0000000000
--- a/client/ayon_core/tools/pyblish_pype/app.css
+++ /dev/null
@@ -1,539 +0,0 @@
-/* Global CSS */
-
-* {
- outline: none;
- color: #ddd;
- font-family: "Open Sans";
- font-style: normal;
-}
-
-/* General CSS */
-
-QWidget {
- background: #555;
- background-position: center center;
- background-repeat: no-repeat;
- font-size: 12px;
-}
-
-QMenu {
- background-color: #555; /* sets background of the menu */
- border: 1px solid #222;
-}
-
-QMenu::item {
- /* sets background of menu item. set this to something non-transparent
- if you want menu color and menu item color to be different */
- background-color: transparent;
- padding: 5px;
- padding-left: 30px;
-}
-
-QMenu::item:selected { /* when user selects item using mouse or keyboard */
- background-color: #666;
-}
-
-QDialog {
- min-width: 300;
- background: "#555";
-}
-
-QListView {
- border: 0px;
- background: "transparent"
-}
-
-QTreeView {
- border: 0px;
- background: "transparent"
-}
-
-QPushButton {
- width: 27px;
- height: 27px;
- background: #555;
- border: 1px solid #aaa;
- border-radius: 4px;
- font-family: "FontAwesome";
- font-size: 11pt;
- color: white;
- padding: 0px;
-}
-
-QPushButton:pressed {
- background: "#777";
-}
-
-QPushButton:hover {
- color: white;
- background: "#666";
-}
-
-QPushButton:disabled {
- color: rgba(255, 255, 255, 50);
-}
-
-QTextEdit, QLineEdit {
- background: #555;
- border: 1px solid #333;
- font-size: 9pt;
- color: #fff;
-}
-
-QCheckBox {
- min-width: 17px;
- max-width: 17px;
- border: 1px solid #222;
- background: transparent;
-}
-
-QCheckBox::indicator {
- width: 15px;
- height: 15px;
- /*background: #444;*/
- background: transparent;
- border: 1px solid #555;
-}
-
-QCheckBox::indicator:checked {
- background: #222;
-}
-
-QComboBox {
- background: #444;
- color: #EEE;
- font-size: 8pt;
- border: 1px solid #333;
- padding: 0px;
-}
-
-QComboBox[combolist="true"]::drop-down {
- background: transparent;
-}
-
-QComboBox[combolist="true"]::down-arrow {
- max-width: 0px;
- width: 1px;
-}
-
-QComboBox[combolist="true"] QAbstractItemView {
- background: #555;
-}
-
-QScrollBar:vertical {
- border: none;
- background: transparent;
- width: 6px;
- margin: 0;
-}
-
-QScrollBar::handle:vertical {
- background: #333;
- border-radius: 3px;
- min-height: 20px;
-}
-
-QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
- height: 0px;
-}
-
-QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {
- border: 1px solid #444;
- width: 3px;
- height: 3px;
- background: white;
-}
-
-QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
- background: none;
-}
-
-QToolTip {
- color: #eee;
- background-color: #555;
- border: none;
- padding: 5px;
-}
-
-QLabel {
- border-radius: 0px;
-}
-
-QToolButton {
- background-color: transparent;
- margin: 0px;
- padding: 0px;
- border-radius: 0px;
- border: none;
-}
-
-/* Specific CSS */
-#PerspectiveToggleBtn {
- border-bottom: 3px solid lightblue;
- border-top: 0px;
- border-radius: 0px;
- border-right: 1px solid #232323;
- border-left: 0px;
- font-size: 26pt;
- font-family: "FontAwesome";
-}
-
-#Terminal QComboBox::drop-down {
- width: 60px;
-}
-
-#Header {
- background: #555;
- border: 1px solid #444;
- padding: 0px;
- margin: 0px;
-}
-
-#Header QRadioButton {
- border: 3px solid "transparent";
- border-right: 1px solid #333;
- left: 2px;
-}
-
-#Header QRadioButton::indicator {
- width: 65px;
- height: 40px;
- background-repeat: no-repeat;
- background-position: center center;
- image: none;
-}
-
-#Header QRadioButton:hover {
- background-color: rgba(255, 255, 255, 10);
-}
-
-#Header QRadioButton:checked {
- background-color: rgba(255, 255, 255, 20);
- border-bottom: 3px solid "lightblue";
-}
-
-#Body {
- padding: 0px;
- border: 1px solid #333;
- background: #444;
-}
-
-#Body QWidget {
- background: #444;
-}
-
-#Header #TerminalTab {
- background-image: url("img/tab-terminal.png");
-}
-
-#Header #OverviewTab {
- background-image: url("img/tab-overview.png");
-}
-
-#ButtonWithMenu {
- background: #555;
- border: 1px solid #fff;
- border-radius: 4px;
- font-family: "FontAwesome";
- font-size: 11pt;
- color: white;
-}
-
-#ButtonWithMenu:pressed {
- background: #777;
-}
-
-#ButtonWithMenu:hover {
- color: white;
- background: #666;
-}
-#ButtonWithMenu:disabled {
- background: #666;
- color: #999;
- border: 1px solid #999;
-}
-
-#FooterSpacer, #FooterInfo, #HeaderSpacer {
- background: transparent;
-}
-
-#Footer {
- background: #555;
- min-height: 43px;
-}
-
-#Footer[success="1"] {
- background: #458056
-}
-
-#Footer[success="0"] {
- background-color: #AA5050
-}
-
-#Footer QPushButton {
- background: #555;
- border: 1px solid #aaa;
- border-radius: 4px;
- font-family: "FontAwesome";
- font-size: 11pt;
- color: white;
- padding: 0px;
-}
-
-#Footer QPushButton:pressed:hover {
- color: #3784c5;
- background: #444;
-}
-
-#Footer QPushButton:hover {
- background: #505050;
- border: 2px solid #3784c5;
-}
-
-#Footer QPushButton:disabled {
- border: 1px solid #888;
- background: #666;
- color: #999;
-}
-
-#ClosingPlaceholder {
- background: rgba(0, 0, 0, 50);
-}
-
-#CommentIntentWidget {
- background: transparent;
-}
-
-#CommentBox, #CommentPlaceholder {
- font-family: "Open Sans";
- font-size: 8pt;
- padding: 5px;
- background: #444;
-}
-
-#CommentBox {
- selection-background-color: #222;
-}
-
-#CommentBox:disabled, #CommentPlaceholder:disabled, #IntentBox:disabled {
- background: #555;
-}
-
-#CommentPlaceholder {
- color: #888
-}
-
-#IntentBox {
- background: #444;
- font-size: 8pt;
- padding: 5px;
- min-width: 75px;
- color: #EEE;
-}
-
-#IntentBox::drop-down:button {
- border: 0px;
- background: transparent;
-}
-
-#IntentBox::down-arrow {
- image: url("/img/down_arrow.png");
-}
-
-#IntentBox::down-arrow:disabled {
- image: url();
-}
-
-#TerminalView {
- background-color: transparent;
-}
-
-#TerminalView:item {
- background-color: transparent;
-}
-
-#TerminalView:hover {
- background-color: transparent;
-}
-
-#TerminalView:selected {
- background-color: transparent;
-}
-
-#TerminalView:item:hover {
- color: #ffffff;
-}
-
-#TerminalView:item:selected {
- color: #eeeeee;
-}
-
-#TerminalView QTextEdit {
- padding:3px;
- color: #aaa;
- border-radius: 7px;
- border-color: #222;
- border-style: solid;
- border-width: 2px;
- background-color: #333;
-}
-
-#TerminalView QTextEdit:hover {
- background-color: #353535;
-}
-
-#TerminalView QTextEdit:selected {
- background-color: #303030;
-}
-
-#ExpandableWidgetContent {
- border: none;
- background-color: #232323;
- color:#eeeeee;
-}
-
-#EllidableLabel {
- font-size: 16pt;
- font-weight: normal;
-}
-
-#PerspectiveScrollContent {
- border: 1px solid #333;
- border-radius: 0px;
-}
-
-#PerspectiveWidgetContent{
- padding: 0px;
-}
-
-#PerspectiveLabel {
- background-color: transparent;
- border: none;
-}
-
-#PerspectiveIndicator {
- font-size: 16pt;
- font-weight: normal;
- padding: 5px;
- background-color: #ffffff;
- color: #333333;
-}
-
-#PerspectiveIndicator[state="warning"] {
- background-color: #ff9900;
- color: #ffffff;
-}
-
-#PerspectiveIndicator[state="active"] {
- background-color: #99CEEE;
- color: #ffffff;
-}
-
-#PerspectiveIndicator[state="error"] {
- background-color: #cc4a4a;
- color: #ffffff;
-}
-
-#PerspectiveIndicator[state="ok"] {
- background-color: #69a567;
- color: #ffffff;
-}
-
-#ExpandableHeader {
- background-color: transparent;
- margin: 0px;
- padding: 0px;
- border-radius: 0px;
- border: none;
-}
-
-#ExpandableHeader QWidget {
- color: #ddd;
-}
-
-#ExpandableHeader QWidget:hover {
- color: #fff;
-}
-
-#TerminalFilterWidget QPushButton {
- /* font: %(font_size_pt)spt; */
- font-family: "FontAwesome";
- text-align: center;
- background-color: transparent;
- border-width: 1px;
- border-color: #777777;
- border-style: none;
- padding: 0px;
- border-radius: 8px;
-}
-#TerminalFilterWidget QPushButton:hover {
- background: #5f5f5f;
- border-style: none;
-}
-#TerminalFilterWidget QPushButton:pressed {
- background: #606060;
- border-style: none;
-}
-#TerminalFilterWidget QPushButton:pressed:hover {
- background: #626262;
- border-style: none;
-}
-
-#TerminalFilerBtn[type="info"]:checked {color: rgb(255, 255, 255);}
-#TerminalFilerBtn[type="info"]:hover:pressed {color: rgba(255, 255, 255, 163);}
-#TerminalFilerBtn[type="info"] {color: rgba(255, 255, 255, 63);}
-
-#TerminalFilerBtn[type="error"]:checked {color: rgb(255, 74, 74);}
-#TerminalFilerBtn[type="error"]:hover:pressed {color: rgba(255, 74, 74, 163);}
-#TerminalFilerBtn[type="error"] {color: rgba(255, 74, 74, 63);}
-
-#TerminalFilerBtn[type="log_debug"]:checked {color: rgb(255, 102, 232);}
-#TerminalFilerBtn[type="log_debug"] {color: rgba(255, 102, 232, 63);}
-#TerminalFilerBtn[type="log_debug"]:hover:pressed {
- color: rgba(255, 102, 232, 163);
-}
-
-#TerminalFilerBtn[type="log_info"]:checked {color: rgb(102, 171, 255);}
-#TerminalFilerBtn[type="log_info"] {color: rgba(102, 171, 255, 63);}
-#TerminalFilerBtn[type="log_info"]:hover:pressed {
- color: rgba(102, 171, 255, 163);
-}
-
-#TerminalFilerBtn[type="log_warning"]:checked {color: rgb(255, 186, 102);}
-#TerminalFilerBtn[type="log_warning"] {color: rgba(255, 186, 102, 63);}
-#TerminalFilerBtn[type="log_warning"]:hover:pressed {
- color: rgba(255, 186, 102, 163);
-}
-
-#TerminalFilerBtn[type="log_error"]:checked {color: rgb(255, 77, 88);}
-#TerminalFilerBtn[type="log_error"] {color: rgba(255, 77, 88, 63);}
-#TerminalFilerBtn[type="log_error"]:hover:pressed {
- color: rgba(255, 77, 88, 163);
-}
-
-#TerminalFilerBtn[type="log_critical"]:checked {color: rgb(255, 79, 117);}
-#TerminalFilerBtn[type="log_critical"] {color: rgba(255, 79, 117, 63);}
-#TerminalFilerBtn[type="log_critical"]:hover:pressed {
- color: rgba(255, 79, 117, 163);
-}
-
-#SuspendLogsBtn {
- background: #444;
- border: none;
- border-top-right-radius: 7px;
- border-bottom-right-radius: 7px;
- border-top-left-radius: 0px;
- border-bottom-left-radius: 0px;
- font-family: "FontAwesome";
- font-size: 11pt;
- color: white;
- padding: 0px;
-}
-
-#SuspendLogsBtn:hover {
- background: #333;
-}
-
-#SuspendLogsBtn:disabled {
- background: #4c4c4c;
-}
diff --git a/client/ayon_core/tools/pyblish_pype/app.py b/client/ayon_core/tools/pyblish_pype/app.py
deleted file mode 100644
index bdc204bfbd..0000000000
--- a/client/ayon_core/tools/pyblish_pype/app.py
+++ /dev/null
@@ -1,110 +0,0 @@
-from __future__ import print_function
-
-import os
-import sys
-import ctypes
-import platform
-import contextlib
-
-from qtpy import QtCore, QtGui, QtWidgets
-
-from . import control, settings, util, window
-
-self = sys.modules[__name__]
-
-# Maintain reference to currently opened window
-self._window = None
-
-
-@contextlib.contextmanager
-def application():
- app = QtWidgets.QApplication.instance()
-
- if not app:
- print("Starting new QApplication..")
- app = QtWidgets.QApplication(sys.argv)
- yield app
- app.exec_()
- else:
- print("Using existing QApplication..")
- yield app
- if os.environ.get("PYBLISH_GUI_ALWAYS_EXEC"):
- app.exec_()
-
-
-def install_translator(app):
- translator = QtCore.QTranslator(app)
- translator.load(QtCore.QLocale.system(), "i18n/",
- directory=util.root)
- app.installTranslator(translator)
- print("Installed translator")
-
-
-def install_fonts():
- database = QtGui.QFontDatabase()
- fonts = [
- "opensans/OpenSans-Bold.ttf",
- "opensans/OpenSans-BoldItalic.ttf",
- "opensans/OpenSans-ExtraBold.ttf",
- "opensans/OpenSans-ExtraBoldItalic.ttf",
- "opensans/OpenSans-Italic.ttf",
- "opensans/OpenSans-Light.ttf",
- "opensans/OpenSans-LightItalic.ttf",
- "opensans/OpenSans-Regular.ttf",
- "opensans/OpenSans-Semibold.ttf",
- "opensans/OpenSans-SemiboldItalic.ttf",
- "fontawesome/fontawesome-webfont.ttf"
- ]
-
- for font in fonts:
- path = util.get_asset("font", font)
-
- # TODO(marcus): Check if they are already installed first.
- # In hosts, this will be called each time the GUI is shown,
- # potentially installing a font each time.
- if database.addApplicationFont(path) < 0:
- print("Could not install %s" % path)
- else:
- print("Installed %s" % font)
-
-
-def on_destroyed():
- """Remove internal reference to window on window destroyed"""
- self._window = None
-
-
-def show(parent=None):
- with open(util.get_asset("app.css")) as f:
- css = f.read()
-
- # Make relative paths absolute
- root = util.get_asset("").replace("\\", "/")
- css = css.replace("url(\"", "url(\"%s" % root)
-
- with application() as app:
-
- if platform.system().lower() == "windows":
- ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
- u"pyblish_pype"
- )
-
- install_fonts()
- install_translator(app)
-
- if self._window is None:
- ctrl = control.Controller()
- self._window = window.Window(ctrl, parent)
- self._window.destroyed.connect(on_destroyed)
-
- self._window.show()
- self._window.activateWindow()
- self._window.setWindowTitle(settings.WindowTitle)
-
- font = QtGui.QFont("Open Sans", 8, QtGui.QFont.Normal)
- self._window.setFont(font)
- self._window.setStyleSheet(css)
-
- self._window.reset()
- self._window.resize(*settings.WindowSize)
-
- return self._window
diff --git a/client/ayon_core/tools/pyblish_pype/awesome.py b/client/ayon_core/tools/pyblish_pype/awesome.py
deleted file mode 100644
index c70f5b1064..0000000000
--- a/client/ayon_core/tools/pyblish_pype/awesome.py
+++ /dev/null
@@ -1,733 +0,0 @@
-
-tags = {
- "500px": u"\uf26e",
- "adjust": u"\uf042",
- "adn": u"\uf170",
- "align-center": u"\uf037",
- "align-justify": u"\uf039",
- "align-left": u"\uf036",
- "align-right": u"\uf038",
- "amazon": u"\uf270",
- "ambulance": u"\uf0f9",
- "american-sign-language-interpreting": u"\uf2a3",
- "anchor": u"\uf13d",
- "android": u"\uf17b",
- "angellist": u"\uf209",
- "angle-double-down": u"\uf103",
- "angle-double-left": u"\uf100",
- "angle-double-right": u"\uf101",
- "angle-double-up": u"\uf102",
- "angle-down": u"\uf107",
- "angle-left": u"\uf104",
- "angle-right": u"\uf105",
- "angle-up": u"\uf106",
- "apple": u"\uf179",
- "archive": u"\uf187",
- "area-chart": u"\uf1fe",
- "arrow-circle-down": u"\uf0ab",
- "arrow-circle-left": u"\uf0a8",
- "arrow-circle-o-down": u"\uf01a",
- "arrow-circle-o-left": u"\uf190",
- "arrow-circle-o-right": u"\uf18e",
- "arrow-circle-o-up": u"\uf01b",
- "arrow-circle-right": u"\uf0a9",
- "arrow-circle-up": u"\uf0aa",
- "arrow-down": u"\uf063",
- "arrow-left": u"\uf060",
- "arrow-right": u"\uf061",
- "arrow-up": u"\uf062",
- "arrows": u"\uf047",
- "arrows-alt": u"\uf0b2",
- "arrows-h": u"\uf07e",
- "arrows-v": u"\uf07d",
- "asl-interpreting (alias)": u"\uf2a3",
- "assistive-listening-systems": u"\uf2a2",
- "asterisk": u"\uf069",
- "at": u"\uf1fa",
- "audio-description": u"\uf29e",
- "automobile (alias)": u"\uf1b9",
- "backward": u"\uf04a",
- "balance-scale": u"\uf24e",
- "ban": u"\uf05e",
- "bank (alias)": u"\uf19c",
- "bar-chart": u"\uf080",
- "bar-chart-o (alias)": u"\uf080",
- "barcode": u"\uf02a",
- "bars": u"\uf0c9",
- "battery-0 (alias)": u"\uf244",
- "battery-1 (alias)": u"\uf243",
- "battery-2 (alias)": u"\uf242",
- "battery-3 (alias)": u"\uf241",
- "battery-4 (alias)": u"\uf240",
- "battery-empty": u"\uf244",
- "battery-full": u"\uf240",
- "battery-half": u"\uf242",
- "battery-quarter": u"\uf243",
- "battery-three-quarters": u"\uf241",
- "bed": u"\uf236",
- "beer": u"\uf0fc",
- "behance": u"\uf1b4",
- "behance-square": u"\uf1b5",
- "bell": u"\uf0f3",
- "bell-o": u"\uf0a2",
- "bell-slash": u"\uf1f6",
- "bell-slash-o": u"\uf1f7",
- "bicycle": u"\uf206",
- "binoculars": u"\uf1e5",
- "birthday-cake": u"\uf1fd",
- "bitbucket": u"\uf171",
- "bitbucket-square": u"\uf172",
- "bitcoin (alias)": u"\uf15a",
- "black-tie": u"\uf27e",
- "blind": u"\uf29d",
- "bluetooth": u"\uf293",
- "bluetooth-b": u"\uf294",
- "bold": u"\uf032",
- "bolt": u"\uf0e7",
- "bomb": u"\uf1e2",
- "book": u"\uf02d",
- "bookmark": u"\uf02e",
- "bookmark-o": u"\uf097",
- "braille": u"\uf2a1",
- "briefcase": u"\uf0b1",
- "btc": u"\uf15a",
- "bug": u"\uf188",
- "building": u"\uf1ad",
- "building-o": u"\uf0f7",
- "bullhorn": u"\uf0a1",
- "bullseye": u"\uf140",
- "bus": u"\uf207",
- "buysellads": u"\uf20d",
- "cab (alias)": u"\uf1ba",
- "calculator": u"\uf1ec",
- "calendar": u"\uf073",
- "calendar-check-o": u"\uf274",
- "calendar-minus-o": u"\uf272",
- "calendar-o": u"\uf133",
- "calendar-plus-o": u"\uf271",
- "calendar-times-o": u"\uf273",
- "camera": u"\uf030",
- "camera-retro": u"\uf083",
- "car": u"\uf1b9",
- "caret-down": u"\uf0d7",
- "caret-left": u"\uf0d9",
- "caret-right": u"\uf0da",
- "caret-square-o-down": u"\uf150",
- "caret-square-o-left": u"\uf191",
- "caret-square-o-right": u"\uf152",
- "caret-square-o-up": u"\uf151",
- "caret-up": u"\uf0d8",
- "cart-arrow-down": u"\uf218",
- "cart-plus": u"\uf217",
- "cc": u"\uf20a",
- "cc-amex": u"\uf1f3",
- "cc-diners-club": u"\uf24c",
- "cc-discover": u"\uf1f2",
- "cc-jcb": u"\uf24b",
- "cc-mastercard": u"\uf1f1",
- "cc-paypal": u"\uf1f4",
- "cc-stripe": u"\uf1f5",
- "cc-visa": u"\uf1f0",
- "certificate": u"\uf0a3",
- "chain (alias)": u"\uf0c1",
- "chain-broken": u"\uf127",
- "check": u"\uf00c",
- "check-circle": u"\uf058",
- "check-circle-o": u"\uf05d",
- "check-square": u"\uf14a",
- "check-square-o": u"\uf046",
- "chevron-circle-down": u"\uf13a",
- "chevron-circle-left": u"\uf137",
- "chevron-circle-right": u"\uf138",
- "chevron-circle-up": u"\uf139",
- "chevron-down": u"\uf078",
- "chevron-left": u"\uf053",
- "chevron-right": u"\uf054",
- "chevron-up": u"\uf077",
- "child": u"\uf1ae",
- "chrome": u"\uf268",
- "circle": u"\uf111",
- "circle-o": u"\uf10c",
- "circle-o-notch": u"\uf1ce",
- "circle-thin": u"\uf1db",
- "clipboard": u"\uf0ea",
- "clock-o": u"\uf017",
- "clone": u"\uf24d",
- "close (alias)": u"\uf00d",
- "cloud": u"\uf0c2",
- "cloud-download": u"\uf0ed",
- "cloud-upload": u"\uf0ee",
- "cny (alias)": u"\uf157",
- "code": u"\uf121",
- "code-fork": u"\uf126",
- "codepen": u"\uf1cb",
- "codiepie": u"\uf284",
- "coffee": u"\uf0f4",
- "cog": u"\uf013",
- "cogs": u"\uf085",
- "columns": u"\uf0db",
- "comment": u"\uf075",
- "comment-o": u"\uf0e5",
- "commenting": u"\uf27a",
- "commenting-o": u"\uf27b",
- "comments": u"\uf086",
- "comments-o": u"\uf0e6",
- "compass": u"\uf14e",
- "compress": u"\uf066",
- "connectdevelop": u"\uf20e",
- "contao": u"\uf26d",
- "copy (alias)": u"\uf0c5",
- "copyright": u"\uf1f9",
- "creative-commons": u"\uf25e",
- "credit-card": u"\uf09d",
- "credit-card-alt": u"\uf283",
- "crop": u"\uf125",
- "crosshairs": u"\uf05b",
- "css3": u"\uf13c",
- "cube": u"\uf1b2",
- "cubes": u"\uf1b3",
- "cut (alias)": u"\uf0c4",
- "cutlery": u"\uf0f5",
- "dashboard (alias)": u"\uf0e4",
- "dashcube": u"\uf210",
- "database": u"\uf1c0",
- "deaf": u"\uf2a4",
- "deafness (alias)": u"\uf2a4",
- "dedent (alias)": u"\uf03b",
- "delicious": u"\uf1a5",
- "desktop": u"\uf108",
- "deviantart": u"\uf1bd",
- "diamond": u"\uf219",
- "digg": u"\uf1a6",
- "dollar (alias)": u"\uf155",
- "dot-circle-o": u"\uf192",
- "download": u"\uf019",
- "dribbble": u"\uf17d",
- "dropbox": u"\uf16b",
- "drupal": u"\uf1a9",
- "edge": u"\uf282",
- "edit (alias)": u"\uf044",
- "eject": u"\uf052",
- "ellipsis-h": u"\uf141",
- "ellipsis-v": u"\uf142",
- "empire": u"\uf1d1",
- "envelope": u"\uf0e0",
- "envelope-o": u"\uf003",
- "envelope-square": u"\uf199",
- "envira": u"\uf299",
- "eraser": u"\uf12d",
- "eur": u"\uf153",
- "euro (alias)": u"\uf153",
- "exchange": u"\uf0ec",
- "exclamation": u"\uf12a",
- "exclamation-circle": u"\uf06a",
- "exclamation-triangle": u"\uf071",
- "expand": u"\uf065",
- "expeditedssl": u"\uf23e",
- "external-link": u"\uf08e",
- "external-link-square": u"\uf14c",
- "eye": u"\uf06e",
- "eye-slash": u"\uf070",
- "eyedropper": u"\uf1fb",
- "fa (alias)": u"\uf2b4",
- "facebook": u"\uf09a",
- "facebook-f (alias)": u"\uf09a",
- "facebook-official": u"\uf230",
- "facebook-square": u"\uf082",
- "fast-backward": u"\uf049",
- "fast-forward": u"\uf050",
- "fax": u"\uf1ac",
- "feed (alias)": u"\uf09e",
- "female": u"\uf182",
- "fighter-jet": u"\uf0fb",
- "file": u"\uf15b",
- "file-archive-o": u"\uf1c6",
- "file-audio-o": u"\uf1c7",
- "file-code-o": u"\uf1c9",
- "file-excel-o": u"\uf1c3",
- "file-image-o": u"\uf1c5",
- "file-movie-o (alias)": u"\uf1c8",
- "file-o": u"\uf016",
- "file-pdf-o": u"\uf1c1",
- "file-photo-o (alias)": u"\uf1c5",
- "file-picture-o (alias)": u"\uf1c5",
- "file-powerpoint-o": u"\uf1c4",
- "file-sound-o (alias)": u"\uf1c7",
- "file-text": u"\uf15c",
- "file-text-o": u"\uf0f6",
- "file-video-o": u"\uf1c8",
- "file-word-o": u"\uf1c2",
- "file-zip-o (alias)": u"\uf1c6",
- "files-o": u"\uf0c5",
- "film": u"\uf008",
- "filter": u"\uf0b0",
- "fire": u"\uf06d",
- "fire-extinguisher": u"\uf134",
- "firefox": u"\uf269",
- "first-order": u"\uf2b0",
- "flag": u"\uf024",
- "flag-checkered": u"\uf11e",
- "flag-o": u"\uf11d",
- "flash (alias)": u"\uf0e7",
- "flask": u"\uf0c3",
- "flickr": u"\uf16e",
- "floppy-o": u"\uf0c7",
- "folder": u"\uf07b",
- "folder-o": u"\uf114",
- "folder-open": u"\uf07c",
- "folder-open-o": u"\uf115",
- "font": u"\uf031",
- "font-awesome": u"\uf2b4",
- "fonticons": u"\uf280",
- "fort-awesome": u"\uf286",
- "forumbee": u"\uf211",
- "forward": u"\uf04e",
- "foursquare": u"\uf180",
- "frown-o": u"\uf119",
- "futbol-o": u"\uf1e3",
- "gamepad": u"\uf11b",
- "gavel": u"\uf0e3",
- "gbp": u"\uf154",
- "ge (alias)": u"\uf1d1",
- "gear (alias)": u"\uf013",
- "gears (alias)": u"\uf085",
- "genderless": u"\uf22d",
- "get-pocket": u"\uf265",
- "gg": u"\uf260",
- "gg-circle": u"\uf261",
- "gift": u"\uf06b",
- "git": u"\uf1d3",
- "git-square": u"\uf1d2",
- "github": u"\uf09b",
- "github-alt": u"\uf113",
- "github-square": u"\uf092",
- "gitlab": u"\uf296",
- "gittip (alias)": u"\uf184",
- "glass": u"\uf000",
- "glide": u"\uf2a5",
- "glide-g": u"\uf2a6",
- "globe": u"\uf0ac",
- "google": u"\uf1a0",
- "google-plus": u"\uf0d5",
- "google-plus-circle (alias)": u"\uf2b3",
- "google-plus-official": u"\uf2b3",
- "google-plus-square": u"\uf0d4",
- "google-wallet": u"\uf1ee",
- "graduation-cap": u"\uf19d",
- "gratipay": u"\uf184",
- "group (alias)": u"\uf0c0",
- "h-square": u"\uf0fd",
- "hacker-news": u"\uf1d4",
- "hand-grab-o (alias)": u"\uf255",
- "hand-lizard-o": u"\uf258",
- "hand-o-down": u"\uf0a7",
- "hand-o-left": u"\uf0a5",
- "hand-o-right": u"\uf0a4",
- "hand-o-up": u"\uf0a6",
- "hand-paper-o": u"\uf256",
- "hand-peace-o": u"\uf25b",
- "hand-pointer-o": u"\uf25a",
- "hand-rock-o": u"\uf255",
- "hand-scissors-o": u"\uf257",
- "hand-spock-o": u"\uf259",
- "hand-stop-o (alias)": u"\uf256",
- "hard-of-hearing (alias)": u"\uf2a4",
- "hashtag": u"\uf292",
- "hdd-o": u"\uf0a0",
- "header": u"\uf1dc",
- "headphones": u"\uf025",
- "heart": u"\uf004",
- "heart-o": u"\uf08a",
- "heartbeat": u"\uf21e",
- "history": u"\uf1da",
- "home": u"\uf015",
- "hospital-o": u"\uf0f8",
- "hotel (alias)": u"\uf236",
- "hourglass": u"\uf254",
- "hourglass-1 (alias)": u"\uf251",
- "hourglass-2 (alias)": u"\uf252",
- "hourglass-3 (alias)": u"\uf253",
- "hourglass-end": u"\uf253",
- "hourglass-half": u"\uf252",
- "hourglass-o": u"\uf250",
- "hourglass-start": u"\uf251",
- "houzz": u"\uf27c",
- "html5": u"\uf13b",
- "i-cursor": u"\uf246",
- "ils": u"\uf20b",
- "image (alias)": u"\uf03e",
- "inbox": u"\uf01c",
- "indent": u"\uf03c",
- "industry": u"\uf275",
- "info": u"\uf129",
- "info-circle": u"\uf05a",
- "inr": u"\uf156",
- "instagram": u"\uf16d",
- "institution (alias)": u"\uf19c",
- "internet-explorer": u"\uf26b",
- "intersex (alias)": u"\uf224",
- "ioxhost": u"\uf208",
- "italic": u"\uf033",
- "joomla": u"\uf1aa",
- "jpy": u"\uf157",
- "jsfiddle": u"\uf1cc",
- "key": u"\uf084",
- "keyboard-o": u"\uf11c",
- "krw": u"\uf159",
- "language": u"\uf1ab",
- "laptop": u"\uf109",
- "lastfm": u"\uf202",
- "lastfm-square": u"\uf203",
- "leaf": u"\uf06c",
- "leanpub": u"\uf212",
- "legal (alias)": u"\uf0e3",
- "lemon-o": u"\uf094",
- "level-down": u"\uf149",
- "level-up": u"\uf148",
- "life-bouy (alias)": u"\uf1cd",
- "life-buoy (alias)": u"\uf1cd",
- "life-ring": u"\uf1cd",
- "life-saver (alias)": u"\uf1cd",
- "lightbulb-o": u"\uf0eb",
- "line-chart": u"\uf201",
- "link": u"\uf0c1",
- "linkedin": u"\uf0e1",
- "linkedin-square": u"\uf08c",
- "linux": u"\uf17c",
- "list": u"\uf03a",
- "list-alt": u"\uf022",
- "list-ol": u"\uf0cb",
- "list-ul": u"\uf0ca",
- "location-arrow": u"\uf124",
- "lock": u"\uf023",
- "long-arrow-down": u"\uf175",
- "long-arrow-left": u"\uf177",
- "long-arrow-right": u"\uf178",
- "long-arrow-up": u"\uf176",
- "low-vision": u"\uf2a8",
- "magic": u"\uf0d0",
- "magnet": u"\uf076",
- "mail-forward (alias)": u"\uf064",
- "mail-reply (alias)": u"\uf112",
- "mail-reply-all (alias)": u"\uf122",
- "male": u"\uf183",
- "map": u"\uf279",
- "map-marker": u"\uf041",
- "map-o": u"\uf278",
- "map-pin": u"\uf276",
- "map-signs": u"\uf277",
- "mars": u"\uf222",
- "mars-double": u"\uf227",
- "mars-stroke": u"\uf229",
- "mars-stroke-h": u"\uf22b",
- "mars-stroke-v": u"\uf22a",
- "maxcdn": u"\uf136",
- "meanpath": u"\uf20c",
- "medium": u"\uf23a",
- "medkit": u"\uf0fa",
- "meh-o": u"\uf11a",
- "mercury": u"\uf223",
- "microphone": u"\uf130",
- "microphone-slash": u"\uf131",
- "minus": u"\uf068",
- "minus-circle": u"\uf056",
- "minus-square": u"\uf146",
- "minus-square-o": u"\uf147",
- "mixcloud": u"\uf289",
- "mobile": u"\uf10b",
- "mobile-phone (alias)": u"\uf10b",
- "modx": u"\uf285",
- "money": u"\uf0d6",
- "moon-o": u"\uf186",
- "mortar-board (alias)": u"\uf19d",
- "motorcycle": u"\uf21c",
- "mouse-pointer": u"\uf245",
- "music": u"\uf001",
- "navicon (alias)": u"\uf0c9",
- "neuter": u"\uf22c",
- "newspaper-o": u"\uf1ea",
- "object-group": u"\uf247",
- "object-ungroup": u"\uf248",
- "odnoklassniki": u"\uf263",
- "odnoklassniki-square": u"\uf264",
- "opencart": u"\uf23d",
- "openid": u"\uf19b",
- "opera": u"\uf26a",
- "optin-monster": u"\uf23c",
- "outdent": u"\uf03b",
- "pagelines": u"\uf18c",
- "paint-brush": u"\uf1fc",
- "paper-plane": u"\uf1d8",
- "paper-plane-o": u"\uf1d9",
- "paperclip": u"\uf0c6",
- "paragraph": u"\uf1dd",
- "paste (alias)": u"\uf0ea",
- "pause": u"\uf04c",
- "pause-circle": u"\uf28b",
- "pause-circle-o": u"\uf28c",
- "paw": u"\uf1b0",
- "paypal": u"\uf1ed",
- "pencil": u"\uf040",
- "pencil-square": u"\uf14b",
- "pencil-square-o": u"\uf044",
- "percent": u"\uf295",
- "phone": u"\uf095",
- "phone-square": u"\uf098",
- "photo (alias)": u"\uf03e",
- "picture-o": u"\uf03e",
- "pie-chart": u"\uf200",
- "pied-piper": u"\uf2ae",
- "pied-piper-alt": u"\uf1a8",
- "pied-piper-pp": u"\uf1a7",
- "pinterest": u"\uf0d2",
- "pinterest-p": u"\uf231",
- "pinterest-square": u"\uf0d3",
- "plane": u"\uf072",
- "play": u"\uf04b",
- "play-circle": u"\uf144",
- "play-circle-o": u"\uf01d",
- "plug": u"\uf1e6",
- "plus": u"\uf067",
- "plus-circle": u"\uf055",
- "plus-square": u"\uf0fe",
- "plus-square-o": u"\uf196",
- "power-off": u"\uf011",
- "print": u"\uf02f",
- "product-hunt": u"\uf288",
- "puzzle-piece": u"\uf12e",
- "qq": u"\uf1d6",
- "qrcode": u"\uf029",
- "question": u"\uf128",
- "question-circle": u"\uf059",
- "question-circle-o": u"\uf29c",
- "quote-left": u"\uf10d",
- "quote-right": u"\uf10e",
- "ra (alias)": u"\uf1d0",
- "random": u"\uf074",
- "rebel": u"\uf1d0",
- "recycle": u"\uf1b8",
- "reddit": u"\uf1a1",
- "reddit-alien": u"\uf281",
- "reddit-square": u"\uf1a2",
- "refresh": u"\uf021",
- "registered": u"\uf25d",
- "remove (alias)": u"\uf00d",
- "renren": u"\uf18b",
- "reorder (alias)": u"\uf0c9",
- "repeat": u"\uf01e",
- "reply": u"\uf112",
- "reply-all": u"\uf122",
- "resistance (alias)": u"\uf1d0",
- "retweet": u"\uf079",
- "rmb (alias)": u"\uf157",
- "road": u"\uf018",
- "rocket": u"\uf135",
- "rotate-left (alias)": u"\uf0e2",
- "rotate-right (alias)": u"\uf01e",
- "rouble (alias)": u"\uf158",
- "rss": u"\uf09e",
- "rss-square": u"\uf143",
- "rub": u"\uf158",
- "ruble (alias)": u"\uf158",
- "rupee (alias)": u"\uf156",
- "safari": u"\uf267",
- "save (alias)": u"\uf0c7",
- "scissors": u"\uf0c4",
- "scribd": u"\uf28a",
- "search": u"\uf002",
- "search-minus": u"\uf010",
- "search-plus": u"\uf00e",
- "sellsy": u"\uf213",
- "send (alias)": u"\uf1d8",
- "send-o (alias)": u"\uf1d9",
- "server": u"\uf233",
- "share": u"\uf064",
- "share-alt": u"\uf1e0",
- "share-alt-square": u"\uf1e1",
- "share-square": u"\uf14d",
- "share-square-o": u"\uf045",
- "shekel (alias)": u"\uf20b",
- "sheqel (alias)": u"\uf20b",
- "shield": u"\uf132",
- "ship": u"\uf21a",
- "shirtsinbulk": u"\uf214",
- "shopping-bag": u"\uf290",
- "shopping-basket": u"\uf291",
- "shopping-cart": u"\uf07a",
- "sign-in": u"\uf090",
- "sign-language": u"\uf2a7",
- "sign-out": u"\uf08b",
- "signal": u"\uf012",
- "signing (alias)": u"\uf2a7",
- "simplybuilt": u"\uf215",
- "sitemap": u"\uf0e8",
- "skyatlas": u"\uf216",
- "skype": u"\uf17e",
- "slack": u"\uf198",
- "sliders": u"\uf1de",
- "slideshare": u"\uf1e7",
- "smile-o": u"\uf118",
- "snapchat": u"\uf2ab",
- "snapchat-ghost": u"\uf2ac",
- "snapchat-square": u"\uf2ad",
- "soccer-ball-o (alias)": u"\uf1e3",
- "sort": u"\uf0dc",
- "sort-alpha-asc": u"\uf15d",
- "sort-alpha-desc": u"\uf15e",
- "sort-amount-asc": u"\uf160",
- "sort-amount-desc": u"\uf161",
- "sort-asc": u"\uf0de",
- "sort-desc": u"\uf0dd",
- "sort-down (alias)": u"\uf0dd",
- "sort-numeric-asc": u"\uf162",
- "sort-numeric-desc": u"\uf163",
- "sort-up (alias)": u"\uf0de",
- "soundcloud": u"\uf1be",
- "space-shuttle": u"\uf197",
- "spinner": u"\uf110",
- "spoon": u"\uf1b1",
- "spotify": u"\uf1bc",
- "square": u"\uf0c8",
- "square-o": u"\uf096",
- "stack-exchange": u"\uf18d",
- "stack-overflow": u"\uf16c",
- "star": u"\uf005",
- "star-half": u"\uf089",
- "star-half-empty (alias)": u"\uf123",
- "star-half-full (alias)": u"\uf123",
- "star-half-o": u"\uf123",
- "star-o": u"\uf006",
- "steam": u"\uf1b6",
- "steam-square": u"\uf1b7",
- "step-backward": u"\uf048",
- "step-forward": u"\uf051",
- "stethoscope": u"\uf0f1",
- "sticky-note": u"\uf249",
- "sticky-note-o": u"\uf24a",
- "stop": u"\uf04d",
- "stop-circle": u"\uf28d",
- "stop-circle-o": u"\uf28e",
- "street-view": u"\uf21d",
- "strikethrough": u"\uf0cc",
- "stumbleupon": u"\uf1a4",
- "stumbleupon-circle": u"\uf1a3",
- "subscript": u"\uf12c",
- "subway": u"\uf239",
- "suitcase": u"\uf0f2",
- "sun-o": u"\uf185",
- "superscript": u"\uf12b",
- "support (alias)": u"\uf1cd",
- "table": u"\uf0ce",
- "tablet": u"\uf10a",
- "tachometer": u"\uf0e4",
- "tag": u"\uf02b",
- "tags": u"\uf02c",
- "tasks": u"\uf0ae",
- "taxi": u"\uf1ba",
- "television": u"\uf26c",
- "tencent-weibo": u"\uf1d5",
- "terminal": u"\uf120",
- "text-height": u"\uf034",
- "text-width": u"\uf035",
- "th": u"\uf00a",
- "th-large": u"\uf009",
- "th-list": u"\uf00b",
- "themeisle": u"\uf2b2",
- "thumb-tack": u"\uf08d",
- "thumbs-down": u"\uf165",
- "thumbs-o-down": u"\uf088",
- "thumbs-o-up": u"\uf087",
- "thumbs-up": u"\uf164",
- "ticket": u"\uf145",
- "times": u"\uf00d",
- "times-circle": u"\uf057",
- "times-circle-o": u"\uf05c",
- "tint": u"\uf043",
- "toggle-down (alias)": u"\uf150",
- "toggle-left (alias)": u"\uf191",
- "toggle-off": u"\uf204",
- "toggle-on": u"\uf205",
- "toggle-right (alias)": u"\uf152",
- "toggle-up (alias)": u"\uf151",
- "trademark": u"\uf25c",
- "train": u"\uf238",
- "transgender": u"\uf224",
- "transgender-alt": u"\uf225",
- "trash": u"\uf1f8",
- "trash-o": u"\uf014",
- "tree": u"\uf1bb",
- "trello": u"\uf181",
- "tripadvisor": u"\uf262",
- "trophy": u"\uf091",
- "truck": u"\uf0d1",
- "try": u"\uf195",
- "tty": u"\uf1e4",
- "tumblr": u"\uf173",
- "tumblr-square": u"\uf174",
- "turkish-lira (alias)": u"\uf195",
- "tv (alias)": u"\uf26c",
- "twitch": u"\uf1e8",
- "twitter": u"\uf099",
- "twitter-square": u"\uf081",
- "umbrella": u"\uf0e9",
- "underline": u"\uf0cd",
- "undo": u"\uf0e2",
- "universal-access": u"\uf29a",
- "university": u"\uf19c",
- "unlink (alias)": u"\uf127",
- "unlock": u"\uf09c",
- "unlock-alt": u"\uf13e",
- "unsorted (alias)": u"\uf0dc",
- "upload": u"\uf093",
- "usb": u"\uf287",
- "usd": u"\uf155",
- "user": u"\uf007",
- "user-md": u"\uf0f0",
- "user-plus": u"\uf234",
- "user-secret": u"\uf21b",
- "user-times": u"\uf235",
- "users": u"\uf0c0",
- "venus": u"\uf221",
- "venus-double": u"\uf226",
- "venus-mars": u"\uf228",
- "viacoin": u"\uf237",
- "viadeo": u"\uf2a9",
- "viadeo-square": u"\uf2aa",
- "video-camera": u"\uf03d",
- "vimeo": u"\uf27d",
- "vimeo-square": u"\uf194",
- "vine": u"\uf1ca",
- "vk": u"\uf189",
- "volume-control-phone": u"\uf2a0",
- "volume-down": u"\uf027",
- "volume-off": u"\uf026",
- "volume-up": u"\uf028",
- "warning (alias)": u"\uf071",
- "wechat (alias)": u"\uf1d7",
- "weibo": u"\uf18a",
- "weixin": u"\uf1d7",
- "whatsapp": u"\uf232",
- "wheelchair": u"\uf193",
- "wheelchair-alt": u"\uf29b",
- "wifi": u"\uf1eb",
- "wikipedia-w": u"\uf266",
- "windows": u"\uf17a",
- "won (alias)": u"\uf159",
- "wordpress": u"\uf19a",
- "wpbeginner": u"\uf297",
- "wpforms": u"\uf298",
- "wrench": u"\uf0ad",
- "xing": u"\uf168",
- "xing-square": u"\uf169",
- "y-combinator": u"\uf23b",
- "y-combinator-square (alias)": u"\uf1d4",
- "yahoo": u"\uf19e",
- "yc (alias)": u"\uf23b",
- "yc-square (alias)": u"\uf1d4",
- "yelp": u"\uf1e9",
- "yen (alias)": u"\uf157",
- "yoast": u"\uf2b1",
- "youtube": u"\uf167",
- "youtube-play": u"\uf16a",
- "youtube-square": u"\uf166"
-}
diff --git a/client/ayon_core/tools/pyblish_pype/constants.py b/client/ayon_core/tools/pyblish_pype/constants.py
deleted file mode 100644
index 10f95ca4af..0000000000
--- a/client/ayon_core/tools/pyblish_pype/constants.py
+++ /dev/null
@@ -1,97 +0,0 @@
-from qtpy import QtCore
-
-EXPANDER_WIDTH = 20
-
-
-def flags(*args, **kwargs):
- type_name = kwargs.pop("type_name", "Flags")
- with_base = kwargs.pop("with_base", False)
- enums = {}
- for idx, attr_name in enumerate(args):
- if with_base:
- if idx == 0:
- enums[attr_name] = 0
- continue
- idx -= 1
- enums[attr_name] = 2**idx
-
- for attr_name, value in kwargs.items():
- enums[attr_name] = value
- return type(type_name, (), enums)
-
-
-def roles(*args, **kwargs):
- type_name = kwargs.pop("type_name", "Roles")
- enums = {}
- for attr_name, value in kwargs.items():
- enums[attr_name] = value
-
- offset = 0
- for idx, attr_name in enumerate(args):
- _idx = idx + QtCore.Qt.UserRole + offset
- while _idx in enums.values():
- offset += 1
- _idx = idx + offset
-
- enums[attr_name] = _idx
-
- return type(type_name, (), enums)
-
-
-Roles = roles(
- "ObjectIdRole",
- "ObjectUIdRole",
- "TypeRole",
- "PublishFlagsRole",
- "LogRecordsRole",
-
- "IsOptionalRole",
- "IsEnabledRole",
-
- "FamiliesRole",
-
- "DocstringRole",
- "PathModuleRole",
- "PluginActionsVisibleRole",
- "PluginValidActionsRole",
- "PluginActionProgressRole",
-
- "TerminalItemTypeRole",
-
- "IntentItemValue",
-
- type_name="ModelRoles"
-)
-
-InstanceStates = flags(
- "ContextType",
- "InProgress",
- "HasWarning",
- "HasError",
- "HasFinished",
- type_name="InstanceState"
-)
-
-PluginStates = flags(
- "IsCompatible",
- "InProgress",
- "WasProcessed",
- "WasSkipped",
- "HasWarning",
- "HasError",
- type_name="PluginState"
-)
-
-GroupStates = flags(
- "HasWarning",
- "HasError",
- "HasFinished",
- type_name="GroupStates"
-)
-
-PluginActionStates = flags(
- "InProgress",
- "HasFailed",
- "HasFinished",
- type_name="PluginActionStates"
-)
diff --git a/client/ayon_core/tools/pyblish_pype/control.py b/client/ayon_core/tools/pyblish_pype/control.py
deleted file mode 100644
index c5034e2736..0000000000
--- a/client/ayon_core/tools/pyblish_pype/control.py
+++ /dev/null
@@ -1,666 +0,0 @@
-"""The Controller in a Model/View/Controller-based application
-The graphical components of Pyblish Lite use this object to perform
-publishing. It communicates via the Qt Signals/Slots mechanism
-and has no direct connection to any graphics. This is important,
-because this is how unittests are able to run without requiring
-an active window manager; such as via Travis-CI.
-"""
-import os
-import sys
-import inspect
-import logging
-import collections
-
-from qtpy import QtCore
-
-import pyblish.api
-import pyblish.util
-import pyblish.logic
-import pyblish.lib
-import pyblish.version
-
-from . import util
-from .constants import InstanceStates
-
-from ayon_core.settings import get_current_project_settings
-
-
-class IterationBreak(Exception):
- pass
-
-
-class MainThreadItem:
- """Callback with args and kwargs."""
- def __init__(self, callback, *args, **kwargs):
- self.callback = callback
- self.args = args
- self.kwargs = kwargs
-
- def process(self):
- self.callback(*self.args, **self.kwargs)
-
-
-class MainThreadProcess(QtCore.QObject):
- """Qt based main thread process executor.
-
- Has timer which controls each 50ms if there is new item to process.
-
- This approach gives ability to update UI meanwhile plugin is in progress.
- """
- # How many times let pass QtApplication to process events
- # - use 2 as resize event can trigger repaint event but not process in
- # same loop
- count_timeout = 2
-
- def __init__(self):
- super(MainThreadProcess, self).__init__()
- self._items_to_process = collections.deque()
-
- timer = QtCore.QTimer()
- timer.setInterval(0)
-
- timer.timeout.connect(self._execute)
-
- self._timer = timer
- self._switch_counter = self.count_timeout
-
- def process(self, func, *args, **kwargs):
- item = MainThreadItem(func, *args, **kwargs)
- self.add_item(item)
-
- def add_item(self, item):
- self._items_to_process.append(item)
-
- def _execute(self):
- if not self._items_to_process:
- return
-
- if self._switch_counter > 0:
- self._switch_counter -= 1
- return
-
- self._switch_counter = self.count_timeout
-
- item = self._items_to_process.popleft()
- item.process()
-
- def start(self):
- if not self._timer.isActive():
- self._timer.start()
-
- def stop(self):
- if self._timer.isActive():
- self._timer.stop()
-
- def clear(self):
- if self._timer.isActive():
- self._timer.stop()
- self._items_to_process = collections.deque()
-
- def stop_if_empty(self):
- if self._timer.isActive():
- item = MainThreadItem(self._stop_if_empty)
- self.add_item(item)
-
- def _stop_if_empty(self):
- if not self._items_to_process:
- self.stop()
-
-
-class Controller(QtCore.QObject):
- log = logging.getLogger("PyblishController")
- # Emitted when the GUI is about to start processing;
- # e.g. resetting, validating or publishing.
- about_to_process = QtCore.Signal(object, object)
-
- # ??? Emitted for each process
- was_processed = QtCore.Signal(dict)
-
- # Emitted when reset
- # - all data are reset (plugins, processing, pari yielder, etc.)
- was_reset = QtCore.Signal()
-
- # Emitted when previous group changed
- passed_group = QtCore.Signal(object)
-
- # Emitted when want to change state of instances
- switch_toggleability = QtCore.Signal(bool)
-
- # On action finished
- was_acted = QtCore.Signal(dict)
-
- # Emitted when processing has stopped
- was_stopped = QtCore.Signal()
-
- # Emitted when processing has finished
- was_finished = QtCore.Signal()
-
- # Emitted when plugin was skipped
- was_skipped = QtCore.Signal(object)
-
- # store OrderGroups - now it is a singleton
- order_groups = util.OrderGroups
-
- # When instance is toggled
- instance_toggled = QtCore.Signal(object, object, object)
-
- def __init__(self, parent=None):
- super(Controller, self).__init__(parent)
- self.context = None
- self.plugins = {}
- self.optional_default = {}
- self.instance_toggled.connect(self._on_instance_toggled)
- self._main_thread_processor = MainThreadProcess()
-
- self._current_state = ""
-
- def reset_variables(self):
- self.log.debug("Resetting pyblish context variables")
-
- # Data internal to the GUI itself
- self.is_running = False
- self.stopped = False
- self.errored = False
- self._current_state = ""
-
- # Active producer of pairs
- self.pair_generator = None
- # Active pair
- self.current_pair = None
-
- # Orders which changes GUI
- # - passing collectors order disables plugin/instance toggle
- self.collect_state = 0
-
- # - passing validators order disables validate button and gives ability
- # to know when to stop on validate button press
- self.validators_order = None
- self.validated = False
-
- # Get collectors and validators order
- plugin_groups_keys = list(self.order_groups.groups.keys())
- self.validators_order = self.order_groups.validation_order
- next_group_order = None
- if len(plugin_groups_keys) > 1:
- next_group_order = plugin_groups_keys[1]
-
- # This is used to track whether or not to continue
- # processing when, for example, validation has failed.
- self.processing = {
- "stop_on_validation": False,
- # Used?
- "last_plugin_order": None,
- "current_group_order": plugin_groups_keys[0],
- "next_group_order": next_group_order,
- "nextOrder": None,
- "ordersWithError": set()
- }
- self._set_state_by_order()
- self.log.debug("Reset of pyblish context variables done")
-
- @property
- def current_state(self):
- return self._current_state
-
- @staticmethod
- def _convert_filter_presets(filter_presets):
- """Convert AYON settings presets to dictionary.
-
- Returns:
- dict[str, dict[str, Any]]: Filter presets converted to dictionary.
- """
- if not isinstance(filter_presets, list):
- return filter_presets
-
- return {
- filter_preset["name"]: {
- item["name"]: item["value"]
- for item in filter_preset["value"]
- }
- for filter_preset in filter_presets
- }
-
- def presets_by_hosts(self):
- # Get global filters as base
- presets = get_current_project_settings()
- if not presets:
- return {}
-
- result = {}
- hosts = pyblish.api.registered_hosts()
- for host in hosts:
- host_presets = presets.get(host, {}).get("filters")
- if not host_presets:
- continue
-
- host_presets = self._convert_filter_presets(host_presets)
-
- for key, value in host_presets.items():
- if value is None:
- if key in result:
- result.pop(key)
- continue
-
- result[key] = value
-
- return result
-
- def reset_context(self):
- self.log.debug("Resetting pyblish context object")
-
- comment = None
- if (
- self.context is not None and
- self.context.data.get("comment") and
- # We only preserve the user typed comment if we are *not*
- # resetting from a successful publish without errors
- self._current_state != "Published"
- ):
- comment = self.context.data["comment"]
-
- self.context = pyblish.api.Context()
-
- self.context._publish_states = InstanceStates.ContextType
- self.context.optional = False
-
- self.context.data["publish"] = True
- self.context.data["name"] = "context"
-
- self.context.data["host"] = reversed(pyblish.api.registered_hosts())
- self.context.data["port"] = int(
- os.environ.get("PYBLISH_CLIENT_PORT", -1)
- )
- self.context.data["connectTime"] = pyblish.lib.time(),
- self.context.data["pyblishVersion"] = pyblish.version,
- self.context.data["pythonVersion"] = sys.version
-
- self.context.data["icon"] = "book"
-
- self.context.families = ("__context__",)
-
- if comment:
- # Preserve comment on reset if user previously had a comment
- self.context.data["comment"] = comment
-
- self.log.debug("Reset of pyblish context object done")
-
- def reset(self):
- """Discover plug-ins and run collection."""
- self._main_thread_processor.clear()
- self._main_thread_processor.process(self._reset)
- self._main_thread_processor.start()
-
- def _reset(self):
- self.reset_context()
- self.reset_variables()
-
- self.possible_presets = self.presets_by_hosts()
-
- # Load plugins and set pair generator
- self.load_plugins()
- self.pair_generator = self._pair_yielder(self.plugins)
-
- self.was_reset.emit()
-
- # Process collectors load rest of plugins with collected instances
- self.collect()
-
- def load_plugins(self):
- self.test = pyblish.logic.registered_test()
- self.optional_default = {}
-
- plugins = pyblish.api.discover()
-
- targets = set(pyblish.logic.registered_targets())
- targets.add("default")
- targets = list(targets)
- plugins_by_targets = pyblish.logic.plugins_by_targets(plugins, targets)
-
- _plugins = []
- for plugin in plugins_by_targets:
- # Skip plugin if is not optional and not active
- if (
- not getattr(plugin, "optional", False)
- and not getattr(plugin, "active", True)
- ):
- continue
- _plugins.append(plugin)
- self.plugins = _plugins
-
- def on_published(self):
- if self.is_running:
- self.is_running = False
- self._current_state = (
- "Published" if not self.errored else "Published, with errors"
- )
- self.was_finished.emit()
- self._main_thread_processor.stop()
-
- def stop(self):
- self.log.debug("Stopping")
- self.stopped = True
-
- def act(self, plugin, action):
- self.is_running = True
- item = MainThreadItem(self._process_action, plugin, action)
- self._main_thread_processor.add_item(item)
- self._main_thread_processor.start()
- self._main_thread_processor.stop_if_empty()
-
- def _process_action(self, plugin, action):
- result = pyblish.plugin.process(
- plugin, self.context, None, action.id
- )
- self.is_running = False
- self.was_acted.emit(result)
-
- def emit_(self, signal, kwargs):
- pyblish.api.emit(signal, **kwargs)
-
- def _process(self, plugin, instance=None):
- """Produce `result` from `plugin` and `instance`
- :func:`process` shares state with :func:`_iterator` such that
- an instance/plugin pair can be fetched and processed in isolation.
- Arguments:
- plugin (pyblish.api.Plugin): Produce result using plug-in
- instance (optional, pyblish.api.Instance): Process this instance,
- if no instance is provided, context is processed.
- """
-
- self.processing["nextOrder"] = plugin.order
-
- try:
- result = pyblish.plugin.process(plugin, self.context, instance)
- # Make note of the order at which the
- # potential error error occurred.
- if result["error"] is not None:
- self.processing["ordersWithError"].add(plugin.order)
-
- except Exception as exc:
- raise Exception("Unknown error({}): {}".format(
- plugin.__name__, str(exc)
- ))
-
- return result
-
- def _pair_yielder(self, plugins):
- for plugin in plugins:
- if (
- self.processing["current_group_order"] is not None
- and plugin.order > self.processing["current_group_order"]
- ):
- current_group_order = self.processing["current_group_order"]
-
- new_next_group_order = None
- new_current_group_order = self.processing["next_group_order"]
- if new_current_group_order is not None:
- current_next_order_found = False
- for order in self.order_groups.groups.keys():
- if current_next_order_found:
- new_next_group_order = order
- break
-
- if order == new_current_group_order:
- current_next_order_found = True
-
- self.processing["next_group_order"] = new_next_group_order
- self.processing["current_group_order"] = (
- new_current_group_order
- )
-
- # Force update to the current state
- self._set_state_by_order()
-
- if self.collect_state == 0:
- self.collect_state = 1
- self._current_state = (
- "Ready" if not self.errored else
- "Collected, with errors"
- )
- self.switch_toggleability.emit(True)
- self.passed_group.emit(current_group_order)
- yield IterationBreak("Collected")
-
- else:
- self.passed_group.emit(current_group_order)
- if self.errored:
- self._current_state = (
- "Stopped, due to errors" if not
- self.processing["stop_on_validation"] else
- "Validated, with errors"
- )
- yield IterationBreak("Last group errored")
-
- if self.collect_state == 1:
- self.collect_state = 2
- self.switch_toggleability.emit(False)
-
- if not self.validated and plugin.order > self.validators_order:
- self.validated = True
- if self.processing["stop_on_validation"]:
- self._current_state = (
- "Validated" if not self.errored else
- "Validated, with errors"
- )
- yield IterationBreak("Validated")
-
- # Stop if was stopped
- if self.stopped:
- self.stopped = False
- self._current_state = "Paused"
- yield IterationBreak("Stopped")
-
- # check test if will stop
- self.processing["nextOrder"] = plugin.order
- message = self.test(**self.processing)
- if message:
- self._current_state = "Paused"
- yield IterationBreak("Stopped due to \"{}\"".format(message))
-
- self.processing["last_plugin_order"] = plugin.order
- if not plugin.active:
- pyblish.logic.log.debug("%s was inactive, skipping.." % plugin)
- self.was_skipped.emit(plugin)
- continue
-
- in_collect_stage = self.collect_state == 0
- if plugin.__instanceEnabled__:
- instances = pyblish.logic.instances_by_plugin(
- self.context, plugin
- )
- if not instances:
- self.was_skipped.emit(plugin)
- continue
-
- for instance in instances:
- if (
- not in_collect_stage
- and instance.data.get("publish") is False
- ):
- pyblish.logic.log.debug(
- "%s was inactive, skipping.." % instance
- )
- continue
- # Stop if was stopped
- if self.stopped:
- self.stopped = False
- self._current_state = "Paused"
- yield IterationBreak("Stopped")
-
- yield (plugin, instance)
- else:
- families = util.collect_families_from_instances(
- self.context, only_active=not in_collect_stage
- )
- plugins = pyblish.logic.plugins_by_families(
- [plugin], families
- )
- if not plugins:
- self.was_skipped.emit(plugin)
- continue
- yield (plugin, None)
-
- self.passed_group.emit(self.processing["next_group_order"])
-
- def iterate_and_process(self, on_finished=None):
- """ Iterating inserted plugins with current context.
- Collectors do not contain instances, they are None when collecting!
- This process don't stop on one
- """
- self._main_thread_processor.start()
-
- def on_next():
- self.log.debug("Looking for next pair to process")
- try:
- self.current_pair = next(self.pair_generator)
- if isinstance(self.current_pair, IterationBreak):
- raise self.current_pair
-
- except IterationBreak:
- self.log.debug("Iteration break was raised")
- self.is_running = False
- self.was_stopped.emit()
- self._main_thread_processor.stop()
- return
-
- except StopIteration:
- self.log.debug("Iteration stop was raised")
- self.is_running = False
- # All pairs were processed successfully!
- if on_finished is not None:
- self._main_thread_processor.add_item(
- MainThreadItem(on_finished)
- )
- self._main_thread_processor.stop_if_empty()
- return
-
- except Exception as exc:
- self.log.warning(
- "Unexpected exception during `on_next` happened",
- exc_info=True
- )
- exc_msg = str(exc)
- self._main_thread_processor.add_item(
- MainThreadItem(on_unexpected_error, error=exc_msg)
- )
- return
-
- self.about_to_process.emit(*self.current_pair)
- self._main_thread_processor.add_item(
- MainThreadItem(on_process)
- )
-
- def on_process():
- try:
- self.log.debug(
- "Processing pair: {}".format(str(self.current_pair))
- )
- result = self._process(*self.current_pair)
- if result["error"] is not None:
- self.log.debug("Error happened")
- self.errored = True
-
- self.log.debug("Pair processed")
- self.was_processed.emit(result)
-
- except Exception as exc:
- self.log.warning(
- "Unexpected exception during `on_process` happened",
- exc_info=True
- )
- exc_msg = str(exc)
- self._main_thread_processor.add_item(
- MainThreadItem(on_unexpected_error, error=exc_msg)
- )
- return
-
- self._main_thread_processor.add_item(
- MainThreadItem(on_next)
- )
-
- def on_unexpected_error(error):
- # TODO this should be handled much differently
- # TODO emit crash signal to show message box with traceback?
- self.is_running = False
- self.was_stopped.emit()
- util.u_print(u"An unexpected error occurred:\n %s" % error)
- if on_finished is not None:
- self._main_thread_processor.add_item(
- MainThreadItem(on_finished)
- )
- self._main_thread_processor.stop_if_empty()
-
- self.is_running = True
- self._main_thread_processor.add_item(
- MainThreadItem(on_next)
- )
-
- def _set_state_by_order(self):
- order = self.processing["current_group_order"]
- self._current_state = self.order_groups.groups[order]["state"]
-
- def collect(self):
- """ Iterate and process Collect plugins
- - load_plugins method is launched again when finished
- """
- self._set_state_by_order()
- self._main_thread_processor.process(self._start_collect)
- self._main_thread_processor.start()
-
- def validate(self):
- """ Process plugins to validations_order value."""
- self._set_state_by_order()
- self._main_thread_processor.process(self._start_validate)
- self._main_thread_processor.start()
-
- def publish(self):
- """ Iterate and process all remaining plugins."""
- self._set_state_by_order()
- self._main_thread_processor.process(self._start_publish)
- self._main_thread_processor.start()
-
- def _start_collect(self):
- self.iterate_and_process()
-
- def _start_validate(self):
- self.processing["stop_on_validation"] = True
- self.iterate_and_process()
-
- def _start_publish(self):
- self.processing["stop_on_validation"] = False
- self.iterate_and_process(self.on_published)
-
- def cleanup(self):
- """Forcefully delete objects from memory
- In an ideal world, this shouldn't be necessary. Garbage
- collection guarantees that anything without reference
- is automatically removed.
- However, because this application is designed to be run
- multiple times from the same interpreter process, extra
- case must be taken to ensure there are no memory leaks.
- Explicitly deleting objects shines a light on where objects
- may still be referenced in the form of an error. No errors
- means this was unnecessary, but that's ok.
- """
-
- for instance in self.context:
- del(instance)
-
- for plugin in self.plugins:
- del(plugin)
-
- def _on_instance_toggled(self, instance, old_value, new_value):
- callbacks = pyblish.api.registered_callbacks().get("instanceToggled")
- if not callbacks:
- return
-
- for callback in callbacks:
- try:
- callback(instance, old_value, new_value)
- except Exception:
- self.log.warning(
- "Callback for `instanceToggled` crashed. {}".format(
- os.path.abspath(inspect.getfile(callback))
- ),
- exc_info=True
- )
diff --git a/client/ayon_core/tools/pyblish_pype/delegate.py b/client/ayon_core/tools/pyblish_pype/delegate.py
deleted file mode 100644
index bb253dd1a3..0000000000
--- a/client/ayon_core/tools/pyblish_pype/delegate.py
+++ /dev/null
@@ -1,540 +0,0 @@
-import platform
-
-from qtpy import QtWidgets, QtGui, QtCore
-
-from . import model
-from .awesome import tags as awesome
-from .constants import (
- PluginStates, InstanceStates, PluginActionStates, Roles, EXPANDER_WIDTH
-)
-
-colors = {
- "error": QtGui.QColor("#ff4a4a"),
- "warning": QtGui.QColor("#ff9900"),
- "ok": QtGui.QColor("#77AE24"),
- "active": QtGui.QColor("#99CEEE"),
- "idle": QtCore.Qt.white,
- "inactive": QtGui.QColor("#888"),
- "hover": QtGui.QColor(255, 255, 255, 10),
- "selected": QtGui.QColor(255, 255, 255, 20),
- "outline": QtGui.QColor("#333"),
- "group": QtGui.QColor("#333"),
- "group-hover": QtGui.QColor("#3c3c3c"),
- "group-selected-hover": QtGui.QColor("#555555"),
- "expander-bg": QtGui.QColor("#222"),
- "expander-hover": QtGui.QColor("#2d6c9f"),
- "expander-selected-hover": QtGui.QColor("#3784c5")
-}
-
-scale_factors = {"darwin": 1.5}
-scale_factor = scale_factors.get(platform.system().lower(), 1.0)
-fonts = {
- "h3": QtGui.QFont("Open Sans", 10 * scale_factor, QtGui.QFont.Normal),
- "h4": QtGui.QFont("Open Sans", 8 * scale_factor, QtGui.QFont.Normal),
- "h5": QtGui.QFont("Open Sans", 8 * scale_factor, QtGui.QFont.DemiBold),
- "awesome6": QtGui.QFont("FontAwesome", 6 * scale_factor),
- "awesome10": QtGui.QFont("FontAwesome", 10 * scale_factor),
- "smallAwesome": QtGui.QFont("FontAwesome", 8 * scale_factor),
- "largeAwesome": QtGui.QFont("FontAwesome", 16 * scale_factor),
-}
-font_metrics = {
- "awesome6": QtGui.QFontMetrics(fonts["awesome6"]),
- "h4": QtGui.QFontMetrics(fonts["h4"]),
- "h5": QtGui.QFontMetrics(fonts["h5"])
-}
-icons = {
- "action": awesome["adn"],
- "angle-right": awesome["angle-right"],
- "angle-left": awesome["angle-left"],
- "plus-sign": awesome['plus'],
- "minus-sign": awesome['minus']
-}
-
-
-class PluginItemDelegate(QtWidgets.QStyledItemDelegate):
- """Generic delegate for model items"""
-
- def paint(self, painter, option, index):
- """Paint checkbox and text.
- _
- |_| My label >
- """
-
- body_rect = QtCore.QRectF(option.rect)
-
- check_rect = QtCore.QRectF(body_rect)
- check_rect.setWidth(check_rect.height())
- check_offset = (check_rect.height() / 4) + 1
- check_rect.adjust(
- check_offset, check_offset, -check_offset, -check_offset
- )
-
- check_color = colors["idle"]
-
- perspective_icon = icons["angle-right"]
- perspective_rect = QtCore.QRectF(body_rect)
- perspective_rect.setWidth(perspective_rect.height())
- perspective_rect.adjust(0, 3, 0, 0)
- perspective_rect.translate(
- body_rect.width() - (perspective_rect.width() / 2 + 2),
- 0
- )
-
- publish_states = index.data(Roles.PublishFlagsRole)
- if publish_states & PluginStates.InProgress:
- check_color = colors["active"]
-
- elif publish_states & PluginStates.HasError:
- check_color = colors["error"]
-
- elif publish_states & PluginStates.HasWarning:
- check_color = colors["warning"]
-
- elif publish_states & PluginStates.WasProcessed:
- check_color = colors["ok"]
-
- elif not index.data(Roles.IsEnabledRole):
- check_color = colors["inactive"]
-
- offset = (body_rect.height() - font_metrics["h4"].height()) / 2
- label_rect = QtCore.QRectF(body_rect.adjusted(
- check_rect.width() + 12, offset - 1, 0, 0
- ))
-
- assert label_rect.width() > 0
-
- label = index.data(QtCore.Qt.DisplayRole)
- label = font_metrics["h4"].elidedText(
- label,
- QtCore.Qt.ElideRight,
- label_rect.width() - 20
- )
-
- font_color = colors["idle"]
- if not index.data(QtCore.Qt.CheckStateRole):
- font_color = colors["inactive"]
-
- # Maintain reference to state, so we can restore it once we're done
- painter.save()
-
- # Draw perspective icon
- painter.setFont(fonts["awesome10"])
- painter.setPen(QtGui.QPen(font_color))
- painter.drawText(perspective_rect, perspective_icon)
-
- # Draw label
- painter.setFont(fonts["h4"])
- painter.setPen(QtGui.QPen(font_color))
- painter.drawText(label_rect, label)
-
- # Draw action icon
- if index.data(Roles.PluginActionsVisibleRole):
- painter.save()
- action_state = index.data(Roles.PluginActionProgressRole)
- if action_state & PluginActionStates.HasFailed:
- color = colors["error"]
- elif action_state & PluginActionStates.HasFinished:
- color = colors["ok"]
- elif action_state & PluginActionStates.InProgress:
- color = colors["active"]
- else:
- color = colors["idle"]
-
- painter.setFont(fonts["smallAwesome"])
- painter.setPen(QtGui.QPen(color))
-
- icon_rect = QtCore.QRectF(
- option.rect.adjusted(
- label_rect.width() - perspective_rect.width() / 2,
- label_rect.height() / 3, 0, 0
- )
- )
- painter.drawText(icon_rect, icons["action"])
-
- painter.restore()
-
- # Draw checkbox
- pen = QtGui.QPen(check_color, 1)
- painter.setPen(pen)
-
- if index.data(Roles.IsOptionalRole):
- painter.drawRect(check_rect)
-
- if index.data(QtCore.Qt.CheckStateRole):
- optional_check_rect = QtCore.QRectF(check_rect)
- optional_check_rect.adjust(2, 2, -1, -1)
- painter.fillRect(optional_check_rect, check_color)
-
- else:
- painter.fillRect(check_rect, check_color)
-
- if option.state & QtWidgets.QStyle.State_MouseOver:
- painter.fillRect(body_rect, colors["hover"])
-
- if option.state & QtWidgets.QStyle.State_Selected:
- painter.fillRect(body_rect, colors["selected"])
-
- # Ok, we're done, tidy up.
- painter.restore()
-
- def sizeHint(self, option, index):
- return QtCore.QSize(option.rect.width(), 20)
-
-
-class InstanceItemDelegate(QtWidgets.QStyledItemDelegate):
- """Generic delegate for model items"""
-
- def paint(self, painter, option, index):
- """Paint checkbox and text.
- _
- |_| My label >
- """
-
- body_rect = QtCore.QRectF(option.rect)
-
- check_rect = QtCore.QRectF(body_rect)
- check_rect.setWidth(check_rect.height())
- offset = (check_rect.height() / 4) + 1
- check_rect.adjust(offset, offset, -(offset), -(offset))
-
- check_color = colors["idle"]
-
- perspective_icon = icons["angle-right"]
- perspective_rect = QtCore.QRectF(body_rect)
- perspective_rect.setWidth(perspective_rect.height())
- perspective_rect.adjust(0, 3, 0, 0)
- perspective_rect.translate(
- body_rect.width() - (perspective_rect.width() / 2 + 2),
- 0
- )
-
- publish_states = index.data(Roles.PublishFlagsRole)
- if publish_states & InstanceStates.InProgress:
- check_color = colors["active"]
-
- elif publish_states & InstanceStates.HasError:
- check_color = colors["error"]
-
- elif publish_states & InstanceStates.HasWarning:
- check_color = colors["warning"]
-
- elif publish_states & InstanceStates.HasFinished:
- check_color = colors["ok"]
-
- elif not index.data(Roles.IsEnabledRole):
- check_color = colors["inactive"]
-
- offset = (body_rect.height() - font_metrics["h4"].height()) / 2
- label_rect = QtCore.QRectF(body_rect.adjusted(
- check_rect.width() + 12, offset - 1, 0, 0
- ))
-
- assert label_rect.width() > 0
-
- label = index.data(QtCore.Qt.DisplayRole)
- label = font_metrics["h4"].elidedText(
- label,
- QtCore.Qt.ElideRight,
- label_rect.width() - 20
- )
-
- font_color = colors["idle"]
- if not index.data(QtCore.Qt.CheckStateRole):
- font_color = colors["inactive"]
-
- # Maintain reference to state, so we can restore it once we're done
- painter.save()
-
- # Draw perspective icon
- painter.setFont(fonts["awesome10"])
- painter.setPen(QtGui.QPen(font_color))
- painter.drawText(perspective_rect, perspective_icon)
-
- # Draw label
- painter.setFont(fonts["h4"])
- painter.setPen(QtGui.QPen(font_color))
- painter.drawText(label_rect, label)
-
- # Draw checkbox
- pen = QtGui.QPen(check_color, 1)
- painter.setPen(pen)
-
- if index.data(Roles.IsOptionalRole):
- painter.drawRect(check_rect)
-
- if index.data(QtCore.Qt.CheckStateRole):
- optional_check_rect = QtCore.QRectF(check_rect)
- optional_check_rect.adjust(2, 2, -1, -1)
- painter.fillRect(optional_check_rect, check_color)
-
- else:
- painter.fillRect(check_rect, check_color)
-
- if option.state & QtWidgets.QStyle.State_MouseOver:
- painter.fillRect(body_rect, colors["hover"])
-
- if option.state & QtWidgets.QStyle.State_Selected:
- painter.fillRect(body_rect, colors["selected"])
-
- # Ok, we're done, tidy up.
- painter.restore()
-
- def sizeHint(self, option, index):
- return QtCore.QSize(option.rect.width(), 20)
-
-
-class InstanceDelegate(QtWidgets.QStyledItemDelegate):
- """Generic delegate for instance header"""
-
- radius = 8.0
-
- def __init__(self, parent):
- super(InstanceDelegate, self).__init__(parent)
- self.item_delegate = InstanceItemDelegate(parent)
-
- def paint(self, painter, option, index):
- if index.data(Roles.TypeRole) in (
- model.InstanceType, model.PluginType
- ):
- self.item_delegate.paint(painter, option, index)
- return
-
- self.group_item_paint(painter, option, index)
-
- def group_item_paint(self, painter, option, index):
- """Paint text
- _
- My label
- """
- body_rect = QtCore.QRectF(option.rect)
- bg_rect = QtCore.QRectF(
- body_rect.left(), body_rect.top() + 1,
- body_rect.width() - 5, body_rect.height() - 2
- )
-
- expander_rect = QtCore.QRectF(bg_rect)
- expander_rect.setWidth(EXPANDER_WIDTH)
-
- remainder_rect = QtCore.QRectF(
- expander_rect.x() + expander_rect.width(),
- expander_rect.y(),
- bg_rect.width() - expander_rect.width(),
- expander_rect.height()
- )
-
- width = float(expander_rect.width())
- height = float(expander_rect.height())
-
- x_pos = expander_rect.x()
- y_pos = expander_rect.y()
-
- x_radius = min(self.radius, width / 2)
- y_radius = min(self.radius, height / 2)
- x_radius2 = x_radius * 2
- y_radius2 = y_radius * 2
-
- expander_path = QtGui.QPainterPath()
- expander_path.moveTo(x_pos, y_pos + y_radius)
- expander_path.arcTo(
- x_pos, y_pos,
- x_radius2, y_radius2,
- 180.0, -90.0
- )
- expander_path.lineTo(x_pos + width, y_pos)
- expander_path.lineTo(x_pos + width, y_pos + height)
- expander_path.lineTo(x_pos + x_radius, y_pos + height)
- expander_path.arcTo(
- x_pos, y_pos + height - y_radius2,
- x_radius2, y_radius2,
- 270.0, -90.0
- )
- expander_path.closeSubpath()
-
- width = float(remainder_rect.width())
- height = float(remainder_rect.height())
- x_pos = remainder_rect.x()
- y_pos = remainder_rect.y()
-
- x_radius = min(self.radius, width / 2)
- y_radius = min(self.radius, height / 2)
- x_radius2 = x_radius * 2
- y_radius2 = y_radius * 2
-
- remainder_path = QtGui.QPainterPath()
- remainder_path.moveTo(x_pos + width, y_pos + height - y_radius)
- remainder_path.arcTo(
- x_pos + width - x_radius2, y_pos + height - y_radius2,
- x_radius2, y_radius2,
- 0.0, -90.0
- )
- remainder_path.lineTo(x_pos, y_pos + height)
- remainder_path.lineTo(x_pos, y_pos)
- remainder_path.lineTo(x_pos + width - x_radius, y_pos)
- remainder_path.arcTo(
- x_pos + width - x_radius2, y_pos,
- x_radius2, y_radius2,
- 90.0, -90.0
- )
- remainder_path.closeSubpath()
-
- painter.fillPath(expander_path, colors["expander-bg"])
- painter.fillPath(remainder_path, colors["group"])
-
- mouse_pos = option.widget.mapFromGlobal(QtGui.QCursor.pos())
- selected = option.state & QtWidgets.QStyle.State_Selected
- hovered = option.state & QtWidgets.QStyle.State_MouseOver
-
- if selected and hovered:
- if expander_rect.contains(mouse_pos):
- painter.fillPath(
- expander_path, colors["expander-selected-hover"]
- )
- else:
- painter.fillPath(
- remainder_path, colors["group-selected-hover"]
- )
-
- elif hovered:
- if expander_rect.contains(mouse_pos):
- painter.fillPath(expander_path, colors["expander-hover"])
- else:
- painter.fillPath(remainder_path, colors["group-hover"])
-
- text_height = font_metrics["awesome6"].height()
- adjust_value = (expander_rect.height() - text_height) / 2
- expander_rect.adjust(
- adjust_value + 1.5, adjust_value - 0.5,
- -adjust_value + 1.5, -adjust_value - 0.5
- )
-
- offset = (remainder_rect.height() - font_metrics["h5"].height()) / 2
- label_rect = QtCore.QRectF(remainder_rect.adjusted(
- 5, offset - 1, 0, 0
- ))
-
- expander_icon = icons["plus-sign"]
-
- expanded = self.parent().isExpanded(index)
- if expanded:
- expander_icon = icons["minus-sign"]
- label = index.data(QtCore.Qt.DisplayRole)
- label = font_metrics["h5"].elidedText(
- label, QtCore.Qt.ElideRight, label_rect.width()
- )
-
- # Maintain reference to state, so we can restore it once we're done
- painter.save()
-
- painter.setFont(fonts["awesome6"])
- painter.setPen(QtGui.QPen(colors["idle"]))
- painter.drawText(expander_rect, QtCore.Qt.AlignCenter, expander_icon)
-
- # Draw label
- painter.setFont(fonts["h5"])
- painter.drawText(label_rect, label)
-
- # Ok, we're done, tidy up.
- painter.restore()
-
- def sizeHint(self, option, index):
- return QtCore.QSize(option.rect.width(), 20)
-
-
-class PluginDelegate(QtWidgets.QStyledItemDelegate):
- """Generic delegate for plugin header"""
-
- def __init__(self, parent):
- super(PluginDelegate, self).__init__(parent)
- self.item_delegate = PluginItemDelegate(parent)
-
- def paint(self, painter, option, index):
- if index.data(Roles.TypeRole) in (
- model.InstanceType, model.PluginType
- ):
- self.item_delegate.paint(painter, option, index)
- return
-
- self.group_item_paint(painter, option, index)
-
- def group_item_paint(self, painter, option, index):
- """Paint text
- _
- My label
- """
- body_rect = QtCore.QRectF(option.rect)
- bg_rect = QtCore.QRectF(
- body_rect.left(), body_rect.top() + 1,
- body_rect.width() - 5, body_rect.height() - 2
- )
- radius = 8.0
- bg_path = QtGui.QPainterPath()
- bg_path.addRoundedRect(bg_rect, radius, radius)
- hovered = option.state & QtWidgets.QStyle.State_MouseOver
- selected = option.state & QtWidgets.QStyle.State_Selected
- if hovered and selected:
- painter.fillPath(bg_path, colors["group-selected-hover"])
- elif hovered:
- painter.fillPath(bg_path, colors["group-hover"])
- else:
- painter.fillPath(bg_path, colors["group"])
-
- expander_rect = QtCore.QRectF(bg_rect)
- expander_rect.setWidth(expander_rect.height())
- text_height = font_metrics["awesome6"].height()
- adjust_value = (expander_rect.height() - text_height) / 2
- expander_rect.adjust(
- adjust_value + 1.5, adjust_value - 0.5,
- -adjust_value + 1.5, -adjust_value - 0.5
- )
-
- offset = (bg_rect.height() - font_metrics["h5"].height()) / 2
- label_rect = QtCore.QRectF(bg_rect.adjusted(
- expander_rect.width() + 12, offset - 1, 0, 0
- ))
-
- assert label_rect.width() > 0
-
- expander_icon = icons["plus-sign"]
-
- expanded = self.parent().isExpanded(index)
- if expanded:
- expander_icon = icons["minus-sign"]
- label = index.data(QtCore.Qt.DisplayRole)
- label = font_metrics["h5"].elidedText(
- label, QtCore.Qt.ElideRight, label_rect.width()
- )
-
- # Maintain reference to state, so we can restore it once we're done
- painter.save()
-
- painter.setFont(fonts["awesome6"])
- painter.setPen(QtGui.QPen(colors["idle"]))
- painter.drawText(expander_rect, QtCore.Qt.AlignCenter, expander_icon)
-
- # Draw label
- painter.setFont(fonts["h5"])
- painter.drawText(label_rect, label)
-
- # Ok, we're done, tidy up.
- painter.restore()
-
- def sizeHint(self, option, index):
- return QtCore.QSize(option.rect.width(), 20)
-
-
-class TerminalItem(QtWidgets.QStyledItemDelegate):
- """Delegate used exclusively for the Terminal"""
-
- def paint(self, painter, option, index):
- super(TerminalItem, self).paint(painter, option, index)
- item_type = index.data(Roles.TypeRole)
- if item_type == model.TerminalDetailType:
- return
-
- hover = QtGui.QPainterPath()
- hover.addRect(QtCore.QRectF(option.rect).adjusted(0, 0, -1, -1))
- if option.state & QtWidgets.QStyle.State_Selected:
- painter.fillPath(hover, colors["selected"])
-
- if option.state & QtWidgets.QStyle.State_MouseOver:
- painter.fillPath(hover, colors["hover"])
diff --git a/client/ayon_core/tools/pyblish_pype/font/fontawesome/fontawesome-webfont.ttf b/client/ayon_core/tools/pyblish_pype/font/fontawesome/fontawesome-webfont.ttf
deleted file mode 100644
index 9d02852c14..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/fontawesome/fontawesome-webfont.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/LICENSE.txt b/client/ayon_core/tools/pyblish_pype/font/opensans/LICENSE.txt
deleted file mode 100644
index d645695673..0000000000
--- a/client/ayon_core/tools/pyblish_pype/font/opensans/LICENSE.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Bold.ttf b/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Bold.ttf
deleted file mode 100644
index fd79d43bea..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Bold.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-BoldItalic.ttf b/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-BoldItalic.ttf
deleted file mode 100644
index 9bc800958a..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-BoldItalic.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-ExtraBold.ttf b/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-ExtraBold.ttf
deleted file mode 100644
index 21f6f84a07..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-ExtraBold.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-ExtraBoldItalic.ttf b/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-ExtraBoldItalic.ttf
deleted file mode 100644
index 31cb688340..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-ExtraBoldItalic.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Italic.ttf b/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Italic.ttf
deleted file mode 100644
index c90da48ff3..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Italic.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Light.ttf b/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Light.ttf
deleted file mode 100644
index 0d381897da..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Light.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-LightItalic.ttf b/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-LightItalic.ttf
deleted file mode 100644
index 68299c4bc6..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-LightItalic.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Regular.ttf b/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Regular.ttf
deleted file mode 100644
index db433349b7..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Regular.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Semibold.ttf b/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Semibold.ttf
deleted file mode 100644
index 1a7679e394..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-Semibold.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-SemiboldItalic.ttf b/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-SemiboldItalic.ttf
deleted file mode 100644
index 59b6d16b06..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/font/opensans/OpenSans-SemiboldItalic.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/i18n/pyblish_lite.pro b/client/ayon_core/tools/pyblish_pype/i18n/pyblish_lite.pro
deleted file mode 100644
index c8e2a5b56f..0000000000
--- a/client/ayon_core/tools/pyblish_pype/i18n/pyblish_lite.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-SOURCES = ../window.py
-TRANSLATIONS = zh_CN.ts
\ No newline at end of file
diff --git a/client/ayon_core/tools/pyblish_pype/i18n/zh_CN.qm b/client/ayon_core/tools/pyblish_pype/i18n/zh_CN.qm
deleted file mode 100644
index fed08d8a51..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/i18n/zh_CN.qm and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/i18n/zh_CN.ts b/client/ayon_core/tools/pyblish_pype/i18n/zh_CN.ts
deleted file mode 100644
index 18ba81f69f..0000000000
--- a/client/ayon_core/tools/pyblish_pype/i18n/zh_CN.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
- Window
-
-
- Finishing up reset..
- 完成重置..
-
-
-
- Comment..
- 备注..
-
-
-
- Processing
- 处理
-
-
-
- Stopped due to error(s), see Terminal.
- 因错误终止, 请查看终端。
-
-
-
- Finished successfully!
- 成功完成!
-
-
-
- About to reset..
- 即将重置..
-
-
-
- Preparing validate..
- 准备校验..
-
-
-
- Preparing publish..
- 准备发布..
-
-
-
- Preparing
- 准备
-
-
-
- Action prepared.
- 动作已就绪。
-
-
-
- Cleaning up models..
- 清理数据模型..
-
-
-
- Cleaning up terminal..
- 清理终端..
-
-
-
- Cleaning up controller..
- 清理控制器..
-
-
-
- All clean!
- 清理完成!
-
-
-
- Good bye
- 再见
-
-
-
- ..as soon as processing is finished..
- ..处理即将完成..
-
-
-
- Stopping..
- 正在停止..
-
-
-
- Closing..
- 正在关闭..
-
-
-
diff --git a/client/ayon_core/tools/pyblish_pype/img/down_arrow.png b/client/ayon_core/tools/pyblish_pype/img/down_arrow.png
deleted file mode 100644
index e271f7f90b..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/img/down_arrow.png and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/img/logo-extrasmall.png b/client/ayon_core/tools/pyblish_pype/img/logo-extrasmall.png
deleted file mode 100644
index ebe45c4c6e..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/img/logo-extrasmall.png and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/img/tab-overview.png b/client/ayon_core/tools/pyblish_pype/img/tab-overview.png
deleted file mode 100644
index 443a750a7c..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/img/tab-overview.png and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/img/tab-terminal.png b/client/ayon_core/tools/pyblish_pype/img/tab-terminal.png
deleted file mode 100644
index ea1bcff98d..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/img/tab-terminal.png and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/mock.py b/client/ayon_core/tools/pyblish_pype/mock.py
deleted file mode 100644
index c85ff0f2ba..0000000000
--- a/client/ayon_core/tools/pyblish_pype/mock.py
+++ /dev/null
@@ -1,732 +0,0 @@
-import os
-import time
-import subprocess
-
-import pyblish.api
-
-
-class MyAction(pyblish.api.Action):
- label = "My Action"
- on = "processed"
-
- def process(self, context, plugin):
- self.log.info("Running!")
-
-
-class MyOtherAction(pyblish.api.Action):
- label = "My Other Action"
-
- def process(self, context, plugin):
- self.log.info("Running!")
-
-
-class CollectComment(pyblish.api.ContextPlugin):
- """This collector has a very long comment.
-
- The idea is that this comment should either be elided, or word-
- wrapped in the corresponding view.
-
- """
-
- order = pyblish.api.CollectorOrder
-
- def process(self, context):
- context.data["comment"] = ""
-
-
-class MyCollector(pyblish.api.ContextPlugin):
- label = "My Collector"
- order = pyblish.api.CollectorOrder
-
- def process(self, context):
- context.create_instance("MyInstance 1", families=["myFamily"])
- context.create_instance("MyInstance 2", families=["myFamily 2"])
- context.create_instance(
- "MyInstance 3",
- families=["myFamily 2"],
- publish=False
- )
-
-
-class MyValidator(pyblish.api.InstancePlugin):
- order = pyblish.api.ValidatorOrder
- active = False
- label = "My Validator"
- actions = [MyAction,
- MyOtherAction]
-
- def process(self, instance):
- self.log.info("Validating: %s" % instance)
-
-
-class MyExtractor(pyblish.api.InstancePlugin):
- order = pyblish.api.ExtractorOrder
- families = ["myFamily"]
- label = "My Extractor"
-
- def process(self, instance):
- self.log.info("Extracting: %s" % instance)
-
-
-class CollectRenamed(pyblish.api.Collector):
- def process(self, context):
- i = context.create_instance("MyInstanceXYZ", family="MyFamily")
- i.set_data("name", "My instance")
-
-
-class CollectNegatron(pyblish.api.Collector):
- """Negative collector adds Negatron"""
-
- order = pyblish.api.Collector.order - 0.49
-
- def process_context(self, context):
- self.log.info("Collecting Negatron")
- context.create_instance("Negatron", family="MyFamily")
-
-
-class CollectPositron(pyblish.api.Collector):
- """Positive collector adds Positron"""
-
- order = pyblish.api.Collector.order + 0.49
-
- def process_context(self, context):
- self.log.info("Collecting Positron")
- context.create_instance("Positron", family="MyFamily")
-
-
-class SelectInstances(pyblish.api.Selector):
- """Select debugging instances
-
- These instances are part of the evil plan to destroy the world.
- Be weary, be vigilant, be sexy.
-
- """
-
- def process_context(self, context):
- self.log.info("Selecting instances..")
-
- for instance in instances[:-1]:
- name, data = instance["name"], instance["data"]
- self.log.info("Selecting: %s" % name)
- instance = context.create_instance(name)
-
- for key, value in data.items():
- instance.set_data(key, value)
-
-
-class SelectDiInstances(pyblish.api.Selector):
- """Select DI instances"""
-
- name = "Select Dependency Instances"
-
- def process(self, context):
- name, data = instances[-1]["name"], instances[-1]["data"]
- self.log.info("Selecting: %s" % name)
- instance = context.create_instance(name)
-
- for key, value in data.items():
- instance.set_data(key, value)
-
-
-class SelectInstancesFailure(pyblish.api.Selector):
- """Select some instances, but fail before adding anything to the context.
-
- That's right. I'm programmed to fail. Try me.
-
- """
-
- __fail__ = True
-
- def process_context(self, context):
- self.log.warning("I'm about to fail")
- raise AssertionError("I was programmed to fail")
-
-
-class SelectInstances2(pyblish.api.Selector):
- def process(self, context):
- self.log.warning("I'm good")
-
-
-class ValidateNamespace(pyblish.api.Validator):
- """Namespaces must be orange
-
- In case a namespace is not orange, report immediately to
- your officer in charge, ask for a refund, do a backflip.
-
- This has been an example of:
-
- - A long doc-string
- - With a list
- - And plenty of newlines and tabs.
-
- """
-
- families = ["B"]
-
- def process(self, instance):
- self.log.info("Validating the namespace of %s" % instance.data("name"))
- self.log.info("""And here's another message, quite long, in fact it's
-too long to be displayed in a single row of text.
-But that's how we roll down here. It's got \nnew lines\nas well.
-
-- And lists
-- And more lists
-
- """)
-
-
-class ValidateContext(pyblish.api.Validator):
- families = ["A", "B"]
-
- def process_context(self, context):
- self.log.info("Processing context..")
-
-
-class ValidateContextFailure(pyblish.api.Validator):
- optional = True
- families = ["C"]
- __fail__ = True
-
- def process_context(self, context):
- self.log.info("About to fail..")
- raise AssertionError("""I was programmed to fail
-
-The reason I failed was because the sun was not aligned with the tides,
-and the moon is gray; not yellow. Try again when the moon is yellow.""")
-
-
-class Validator1(pyblish.api.Validator):
- """Test of the order attribute"""
- order = pyblish.api.Validator.order + 0.1
- families = ["A"]
-
- def process_instance(self, instance):
- pass
-
-
-class Validator2(pyblish.api.Validator):
- order = pyblish.api.Validator.order + 0.2
- families = ["B"]
-
- def process_instance(self, instance):
- pass
-
-
-class Validator3(pyblish.api.Validator):
- order = pyblish.api.Validator.order + 0.3
- families = ["B"]
-
- def process_instance(self, instance):
- pass
-
-
-class ValidateFailureMock(pyblish.api.Validator):
- """Plug-in that always fails"""
- optional = True
- order = pyblish.api.Validator.order + 0.1
- families = ["C"]
- __fail__ = True
-
- def process_instance(self, instance):
- self.log.debug("e = mc^2")
- self.log.info("About to fail..")
- self.log.warning("Failing.. soooon..")
- self.log.critical("Ok, you're done.")
- raise AssertionError("""ValidateFailureMock was destined to fail..
-
-Here's some extended information about what went wrong.
-
-It has quite the long string associated with it, including
-a few newlines and a list.
-
-- Item 1
-- Item 2
-
-""")
-
-
-class ValidateIsIncompatible(pyblish.api.Validator):
- """This plug-in should never appear.."""
- requires = False # This is invalid
-
-
-class ValidateWithRepair(pyblish.api.Validator):
- """A validator with repair functionality"""
- optional = True
- families = ["C"]
- __fail__ = True
-
- def process_instance(self, instance):
- raise AssertionError(
- "%s is invalid, try repairing it!" % instance.name
- )
-
- def repair_instance(self, instance):
- self.log.info("Attempting to repair..")
- self.log.info("Success!")
-
-
-class ValidateWithRepairFailure(pyblish.api.Validator):
- """A validator with repair functionality that fails"""
- optional = True
- families = ["C"]
- __fail__ = True
-
- def process_instance(self, instance):
- raise AssertionError(
- "%s is invalid, try repairing it!" % instance.name
- )
-
- def repair_instance(self, instance):
- self.log.info("Attempting to repair..")
- raise AssertionError("Could not repair due to X")
-
-
-class ValidateWithVeryVeryVeryLongLongNaaaaame(pyblish.api.Validator):
- """A validator with repair functionality that fails"""
- families = ["A"]
-
-
-class ValidateWithRepairContext(pyblish.api.Validator):
- """A validator with repair functionality that fails"""
- optional = True
- families = ["C"]
- __fail__ = True
-
- def process_context(self, context):
- raise AssertionError("Could not validate context, try repairing it")
-
- def repair_context(self, context):
- self.log.info("Attempting to repair..")
- raise AssertionError("Could not repair")
-
-
-class ExtractAsMa(pyblish.api.Extractor):
- """Extract contents of each instance into .ma
-
- Serialise scene using Maya's own facilities and then put
- it on the hard-disk. Once complete, this plug-in relies
- on a Conformer to put it in it's final location, as this
- extractor merely positions it in the users local temp-
- directory.
-
- """
-
- optional = True
- __expected__ = {
- "logCount": ">=4"
- }
-
- def process_instance(self, instance):
- self.log.info("About to extract scene to .ma..")
- self.log.info("Extraction went well, now verifying the data..")
-
- if instance.name == "Richard05":
- self.log.warning("You're almost running out of disk space!")
-
- self.log.info("About to finish up")
- self.log.info("Finished successfully")
-
-
-class ConformAsset(pyblish.api.Conformer):
- """Conform the world
-
- Step 1: Conform all humans and Step 2: Conform all non-humans.
- Once conforming has completed, rinse and repeat.
-
- """
-
- optional = True
-
- def process_instance(self, instance):
- self.log.info("About to conform all humans..")
-
- if instance.name == "Richard05":
- self.log.warning("Richard05 is a conformist!")
-
- self.log.info("About to conform all non-humans..")
- self.log.info("Conformed Successfully")
-
-
-class ValidateInstancesDI(pyblish.api.Validator):
- """Validate using the DI interface"""
- families = ["diFamily"]
-
- def process(self, instance):
- self.log.info("Validating %s.." % instance.data("name"))
-
-
-class ValidateDIWithRepair(pyblish.api.Validator):
- families = ["diFamily"]
- optional = True
- __fail__ = True
-
- def process(self, instance):
- raise AssertionError("I was programmed to fail, for repair")
-
- def repair(self, instance):
- self.log.info("Repairing %s" % instance.data("name"))
-
-
-class ExtractInstancesDI(pyblish.api.Extractor):
- """Extract using the DI interface"""
- families = ["diFamily"]
-
- def process(self, instance):
- self.log.info("Extracting %s.." % instance.data("name"))
-
-
-class ValidateWithLabel(pyblish.api.Validator):
- """Validate using the DI interface"""
- label = "Validate with Label"
-
-
-class ValidateWithLongLabel(pyblish.api.Validator):
- """Validate using the DI interface"""
- label = "Validate with Loooooooooooooooooooooong Label"
-
-
-class SimplePlugin1(pyblish.api.Plugin):
- """Validate using the simple-plugin interface"""
-
- def process(self):
- self.log.info("I'm a simple plug-in, only processed once")
-
-
-class SimplePlugin2(pyblish.api.Plugin):
- """Validate using the simple-plugin interface
-
- It doesn't have an order, and will likely end up *before* all
- other plug-ins. (due to how sorted([1, 2, 3, None]) works)
-
- """
-
- def process(self, context):
- self.log.info("Processing the context, simply: %s" % context)
-
-
-class SimplePlugin3(pyblish.api.Plugin):
- """Simply process every instance"""
-
- def process(self, instance):
- self.log.info("Processing the instance, simply: %s" % instance)
-
-
-class ContextAction(pyblish.api.Action):
- label = "Context action"
-
- def process(self, context):
- self.log.info("I have access to the context")
- self.log.info("Context.instances: %s" % str(list(context)))
-
-
-class FailingAction(pyblish.api.Action):
- label = "Failing action"
-
- def process(self):
- self.log.info("About to fail..")
- raise Exception("I failed")
-
-
-class LongRunningAction(pyblish.api.Action):
- label = "Long-running action"
-
- def process(self):
- self.log.info("Sleeping for 2 seconds..")
- time.sleep(2)
- self.log.info("Ah, that's better")
-
-
-class IconAction(pyblish.api.Action):
- label = "Icon action"
- icon = "crop"
-
- def process(self):
- self.log.info("I have an icon")
-
-
-class PluginAction(pyblish.api.Action):
- label = "Plugin action"
-
- def process(self, plugin):
- self.log.info("I have access to my parent plug-in")
- self.log.info("Which is %s" % plugin.id)
-
-
-class LaunchExplorerAction(pyblish.api.Action):
- label = "Open in Explorer"
- icon = "folder-open"
-
- def process(self, context):
- cwd = os.getcwd()
- self.log.info("Opening %s in Explorer" % cwd)
- result = subprocess.call("start .", cwd=cwd, shell=True)
- self.log.debug(result)
-
-
-class ProcessedAction(pyblish.api.Action):
- label = "Success action"
- icon = "check"
- on = "processed"
-
- def process(self):
- self.log.info("I am only available on a successful plug-in")
-
-
-class FailedAction(pyblish.api.Action):
- label = "Failure action"
- icon = "close"
- on = "failed"
-
-
-class SucceededAction(pyblish.api.Action):
- label = "Success action"
- icon = "check"
- on = "succeeded"
-
- def process(self):
- self.log.info("I am only available on a successful plug-in")
-
-
-class LongLabelAction(pyblish.api.Action):
- label = "An incredibly, incredicly looooon label. Very long."
- icon = "close"
-
-
-class BadEventAction(pyblish.api.Action):
- label = "Bad event action"
- on = "not exist"
-
-
-class InactiveAction(pyblish.api.Action):
- active = False
-
-
-class PluginWithActions(pyblish.api.Validator):
- optional = True
- actions = [
- pyblish.api.Category("General"),
- ContextAction,
- FailingAction,
- LongRunningAction,
- IconAction,
- PluginAction,
- pyblish.api.Category("Empty"),
- pyblish.api.Category("OS"),
- LaunchExplorerAction,
- pyblish.api.Separator,
- FailedAction,
- SucceededAction,
- pyblish.api.Category("Debug"),
- BadEventAction,
- InactiveAction,
- LongLabelAction,
- pyblish.api.Category("Empty"),
- ]
-
- def process(self):
- self.log.info("Ran PluginWithActions")
-
-
-class FailingPluginWithActions(pyblish.api.Validator):
- optional = True
- actions = [
- FailedAction,
- SucceededAction,
- ]
-
- def process(self):
- raise Exception("I was programmed to fail")
-
-
-class ValidateDefaultOff(pyblish.api.Validator):
- families = ["A", "B"]
- active = False
- optional = True
-
- def process(self, instance):
- self.log.info("Processing instance..")
-
-
-class ValidateWithHyperlinks(pyblish.api.Validator):
- """To learn about Pyblish
-
- click here (http://pyblish.com)
-
- """
-
- families = ["A", "B"]
-
- def process(self, instance):
- self.log.info("Processing instance..")
-
- msg = "To learn about Pyblish, "
- msg += "click here (http://pyblish.com)"
-
- self.log.info(msg)
-
-
-class LongRunningCollector(pyblish.api.Collector):
- """I will take at least 2 seconds..."""
- def process(self, context):
- self.log.info("Sleeping for 2 seconds..")
- time.sleep(2)
- self.log.info("Good morning")
-
-
-class LongRunningValidator(pyblish.api.Validator):
- """I will take at least 2 seconds..."""
- def process(self, context):
- self.log.info("Sleeping for 2 seconds..")
- time.sleep(2)
- self.log.info("Good morning")
-
-
-class RearrangingPlugin(pyblish.api.ContextPlugin):
- """Sort plug-ins by family, and then reverse it"""
- order = pyblish.api.CollectorOrder + 0.2
-
- def process(self, context):
- self.log.info("Reversing instances in the context..")
- context[:] = sorted(
- context,
- key=lambda i: i.data["family"],
- reverse=True
- )
- self.log.info("Reversed!")
-
-
-class InactiveInstanceCollectorPlugin(pyblish.api.InstancePlugin):
- """Special case of an InstancePlugin running as a Collector"""
- order = pyblish.api.CollectorOrder + 0.1
- active = False
-
- def process(self, instance):
- raise TypeError("I shouldn't have run in the first place")
-
-
-class CollectWithIcon(pyblish.api.ContextPlugin):
- order = pyblish.api.CollectorOrder
-
- def process(self, context):
- instance = context.create_instance("With Icon")
- instance.data["icon"] = "play"
-
-
-instances = [
- {
- "name": "Peter01",
- "data": {
- "family": "A",
- "publish": False
- }
- },
- {
- "name": "Richard05",
- "data": {
- "family": "A",
- }
- },
- {
- "name": "Steven11",
- "data": {
- "family": "B",
- }
- },
- {
- "name": "Piraya12",
- "data": {
- "family": "B",
- }
- },
- {
- "name": "Marcus",
- "data": {
- "family": "C",
- }
- },
- {
- "name": "Extra1",
- "data": {
- "family": "C",
- }
- },
- {
- "name": "DependencyInstance",
- "data": {
- "family": "diFamily"
- }
- },
- {
- "name": "NoFamily",
- "data": {}
- },
- {
- "name": "Failure 1",
- "data": {
- "family": "failure",
- "fail": False
- }
- },
- {
- "name": "Failure 2",
- "data": {
- "family": "failure",
- "fail": True
- }
- }
-]
-
-plugins = [
- MyCollector,
- MyValidator,
- MyExtractor,
-
- CollectRenamed,
- CollectNegatron,
- CollectPositron,
- SelectInstances,
- SelectInstances2,
- SelectDiInstances,
- SelectInstancesFailure,
- ValidateFailureMock,
- ValidateNamespace,
- # ValidateIsIncompatible,
- ValidateWithVeryVeryVeryLongLongNaaaaame,
- ValidateContext,
- ValidateContextFailure,
- Validator1,
- Validator2,
- Validator3,
- ValidateWithRepair,
- ValidateWithRepairFailure,
- ValidateWithRepairContext,
- ValidateWithLabel,
- ValidateWithLongLabel,
- ValidateDefaultOff,
- ValidateWithHyperlinks,
- ExtractAsMa,
- ConformAsset,
-
- SimplePlugin1,
- SimplePlugin2,
- SimplePlugin3,
-
- ValidateInstancesDI,
- ExtractInstancesDI,
- ValidateDIWithRepair,
-
- PluginWithActions,
- FailingPluginWithActions,
-
- # LongRunningCollector,
- # LongRunningValidator,
-
- RearrangingPlugin,
- InactiveInstanceCollectorPlugin,
-
- CollectComment,
- CollectWithIcon,
-]
-
-pyblish.api.sort_plugins(plugins)
diff --git a/client/ayon_core/tools/pyblish_pype/model.py b/client/ayon_core/tools/pyblish_pype/model.py
deleted file mode 100644
index 44f951fe14..0000000000
--- a/client/ayon_core/tools/pyblish_pype/model.py
+++ /dev/null
@@ -1,1116 +0,0 @@
-"""Qt models
-
-Description:
- The model contains the original objects from Pyblish, such as
- pyblish.api.Instance and pyblish.api.Plugin. The model then
- provides an interface for reading and writing to those.
-
-GUI data:
- Aside from original data, such as pyblish.api.Plugin.optional,
- the GUI also hosts data internal to itself, such as whether or
- not an item has processed such that it may be colored appropriately
- in the view. This data is prefixed with two underscores (__).
-
- E.g.
-
- _has_processed
-
- This is so that the the GUI-only data doesn't accidentally overwrite
- or cause confusion with existing data in plug-ins and instances.
-
-Roles:
- Data is accessed via standard Qt "roles". You can think of a role
- as the key of a dictionary, except they can only be integers.
-
-"""
-from __future__ import unicode_literals
-
-import pyblish
-
-from . import settings, util
-from .awesome import tags as awesome
-from qtpy import QtCore, QtGui
-import qtawesome
-from .constants import PluginStates, InstanceStates, GroupStates, Roles
-
-
-# ItemTypes
-UserType = QtGui.QStandardItem.UserType
-if hasattr(UserType, "value"):
- UserType = UserType.value
-InstanceType = UserType
-PluginType = UserType + 1
-GroupType = UserType + 2
-TerminalLabelType = UserType + 3
-TerminalDetailType = UserType + 4
-
-
-class QAwesomeTextIconFactory:
- icons = {}
-
- @classmethod
- def icon(cls, icon_name):
- if icon_name not in cls.icons:
- cls.icons[icon_name] = awesome.get(icon_name)
- return cls.icons[icon_name]
-
-
-class QAwesomeIconFactory:
- icons = {}
-
- @classmethod
- def icon(cls, icon_name, icon_color):
- if icon_name not in cls.icons:
- cls.icons[icon_name] = {}
-
- if icon_color not in cls.icons[icon_name]:
- cls.icons[icon_name][icon_color] = qtawesome.icon(
- icon_name,
- color=icon_color
- )
- return cls.icons[icon_name][icon_color]
-
-
-class IntentModel(QtGui.QStandardItemModel):
- """Model for QComboBox with intents.
-
- It is expected that one inserted item is dictionary.
- Key represents #Label and Value represent #Value.
-
- Example:
- {
- "Testing": "test",
- "Publishing": "publish"
- }
-
- First and default value is {"< Not Set >": None}
- """
-
- default_empty_label = "< Not set >"
-
- def __init__(self, parent=None):
- super(IntentModel, self).__init__(parent)
- self._item_count = 0
- self.default_index = 0
-
- @property
- def has_items(self):
- return self._item_count > 0
-
- def reset(self):
- self.clear()
- self._item_count = 0
- self.default_index = 0
-
- # Intent settings are not available in core addon
- intent_settings = {}
-
- items = intent_settings.get("items", {})
- if not items:
- return
-
- allow_empty_intent = intent_settings.get("allow_empty_intent", True)
- empty_intent_label = (
- intent_settings.get("empty_intent_label")
- or self.default_empty_label
- )
- listed_items = list(items.items())
- if allow_empty_intent:
- listed_items.insert(0, ("", empty_intent_label))
-
- default = intent_settings.get("default")
-
- for idx, item in enumerate(listed_items):
- item_value = item[0]
- if item_value == default:
- self.default_index = idx
- break
-
- self._add_items(listed_items)
-
- def _add_items(self, items):
- for item in items:
- value, label = item
- new_item = QtGui.QStandardItem()
- new_item.setData(label, QtCore.Qt.DisplayRole)
- new_item.setData(value, Roles.IntentItemValue)
-
- self.setItem(self._item_count, new_item)
- self._item_count += 1
-
-
-class PluginItem(QtGui.QStandardItem):
- """Plugin item implementation."""
-
- def __init__(self, plugin):
- super(PluginItem, self).__init__()
-
- item_text = plugin.__name__
- if settings.UseLabel:
- if hasattr(plugin, "label") and plugin.label:
- item_text = plugin.label
-
- self.plugin = plugin
-
- self.setData(item_text, QtCore.Qt.DisplayRole)
- self.setData(False, Roles.IsEnabledRole)
- self.setData(0, Roles.PublishFlagsRole)
- self.setData(0, Roles.PluginActionProgressRole)
- icon_name = ""
- if hasattr(plugin, "icon") and plugin.icon:
- icon_name = plugin.icon
- icon = QAwesomeTextIconFactory.icon(icon_name)
- self.setData(icon, QtCore.Qt.DecorationRole)
-
- actions = []
- if hasattr(plugin, "actions") and plugin.actions:
- actions = list(plugin.actions)
- plugin.actions = actions
-
- is_checked = True
- is_optional = getattr(plugin, "optional", False)
- if is_optional:
- is_checked = getattr(plugin, "active", True)
-
- plugin.active = is_checked
- plugin.optional = is_optional
-
- self.setData(
- "{}.{}".format(plugin.__module__, plugin.__name__),
- Roles.ObjectUIdRole
- )
-
- self.setFlags(
- QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
- )
-
- def type(self):
- return PluginType
-
- def data(self, role=QtCore.Qt.DisplayRole):
- if role == Roles.IsOptionalRole:
- return self.plugin.optional
-
- if role == Roles.ObjectIdRole:
- return self.plugin.id
-
- if role == Roles.TypeRole:
- return self.type()
-
- if role == QtCore.Qt.CheckStateRole:
- return self.plugin.active
-
- if role == Roles.PathModuleRole:
- return self.plugin.__module__
-
- if role == Roles.FamiliesRole:
- return self.plugin.families
-
- if role == Roles.DocstringRole:
- return self.plugin.__doc__
-
- if role == Roles.PluginActionsVisibleRole:
- return self._data_actions_visible()
-
- if role == Roles.PluginValidActionsRole:
- return self._data_valid_actions()
-
- return super(PluginItem, self).data(role)
-
- def _data_actions_visible(self):
- # Can only run actions on active plug-ins.
- if not self.plugin.active or not self.plugin.actions:
- return False
-
- publish_states = self.data(Roles.PublishFlagsRole)
- if (
- not publish_states & PluginStates.IsCompatible
- or publish_states & PluginStates.WasSkipped
- ):
- return False
-
- # Context specific actions
- for action in self.plugin.actions:
- if action.on == "failed":
- if publish_states & PluginStates.HasError:
- return True
-
- elif action.on == "succeeded":
- if (
- publish_states & PluginStates.WasProcessed
- and not publish_states & PluginStates.HasError
- ):
- return True
-
- elif action.on == "processed":
- if publish_states & PluginStates.WasProcessed:
- return True
-
- elif action.on == "notProcessed":
- if not publish_states & PluginStates.WasProcessed:
- return True
- return False
-
- def _data_valid_actions(self):
- valid_actions = []
-
- # Can only run actions on active plug-ins.
- if not self.plugin.active or not self.plugin.actions:
- return valid_actions
-
- if not self.plugin.active or not self.plugin.actions:
- return False
-
- publish_states = self.data(Roles.PublishFlagsRole)
- if (
- not publish_states & PluginStates.IsCompatible
- or publish_states & PluginStates.WasSkipped
- ):
- return False
-
- # Context specific actions
- for action in self.plugin.actions:
- valid = False
- if action.on == "failed":
- if publish_states & PluginStates.HasError:
- valid = True
-
- elif action.on == "succeeded":
- if (
- publish_states & PluginStates.WasProcessed
- and not publish_states & PluginStates.HasError
- ):
- valid = True
-
- elif action.on == "processed":
- if publish_states & PluginStates.WasProcessed:
- valid = True
-
- elif action.on == "notProcessed":
- if not publish_states & PluginStates.WasProcessed:
- valid = True
-
- if valid:
- valid_actions.append(action)
-
- if not valid_actions:
- return valid_actions
-
- actions_len = len(valid_actions)
- # Discard empty groups
- indexex_to_remove = []
- for idx, action in enumerate(valid_actions):
- if action.__type__ != "category":
- continue
-
- next_id = idx + 1
- if next_id >= actions_len:
- indexex_to_remove.append(idx)
- continue
-
- next = valid_actions[next_id]
- if next.__type__ != "action":
- indexex_to_remove.append(idx)
-
- for idx in reversed(indexex_to_remove):
- valid_actions.pop(idx)
-
- return valid_actions
-
- def setData(self, value, role=None):
- if role is None:
- role = QtCore.Qt.UserRole + 1
-
- if role == QtCore.Qt.CheckStateRole:
- if not self.data(Roles.IsEnabledRole):
- return False
- self.plugin.active = value
- self.emitDataChanged()
- return
-
- elif role == Roles.PluginActionProgressRole:
- if isinstance(value, list):
- _value = self.data(Roles.PluginActionProgressRole)
- for flag in value:
- _value |= flag
- value = _value
-
- elif isinstance(value, dict):
- _value = self.data(Roles.PluginActionProgressRole)
- for flag, _bool in value.items():
- if _bool is True:
- _value |= flag
- elif _value & flag:
- _value ^= flag
- value = _value
-
- elif role == Roles.PublishFlagsRole:
- if isinstance(value, list):
- _value = self.data(Roles.PublishFlagsRole)
- for flag in value:
- _value |= flag
- value = _value
-
- elif isinstance(value, dict):
- _value = self.data(Roles.PublishFlagsRole)
- for flag, _bool in value.items():
- if _bool is True:
- _value |= flag
- elif _value & flag:
- _value ^= flag
- value = _value
-
- if value & PluginStates.HasWarning:
- if self.parent():
- self.parent().setData(
- {GroupStates.HasWarning: True},
- Roles.PublishFlagsRole
- )
- if value & PluginStates.HasError:
- if self.parent():
- self.parent().setData(
- {GroupStates.HasError: True},
- Roles.PublishFlagsRole
- )
-
- return super(PluginItem, self).setData(value, role)
-
-
-class GroupItem(QtGui.QStandardItem):
- def __init__(self, *args, **kwargs):
- self.order = kwargs.pop("order", None)
- self.publish_states = 0
- super(GroupItem, self).__init__(*args, **kwargs)
-
- def flags(self):
- return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
-
- def data(self, role=QtCore.Qt.DisplayRole):
- if role == Roles.PublishFlagsRole:
- return self.publish_states
-
- if role == Roles.TypeRole:
- return self.type()
-
- return super(GroupItem, self).data(role)
-
- def setData(self, value, role=(QtCore.Qt.UserRole + 1)):
- if role == Roles.PublishFlagsRole:
- if isinstance(value, list):
- _value = self.data(Roles.PublishFlagsRole)
- for flag in value:
- _value |= flag
- value = _value
-
- elif isinstance(value, dict):
- _value = self.data(Roles.PublishFlagsRole)
- for flag, _bool in value.items():
- if _bool is True:
- _value |= flag
- elif _value & flag:
- _value ^= flag
- value = _value
- self.publish_states = value
- self.emitDataChanged()
- return True
-
- return super(GroupItem, self).setData(value, role)
-
- def type(self):
- return GroupType
-
-
-class PluginModel(QtGui.QStandardItemModel):
- def __init__(self, controller, *args, **kwargs):
- super(PluginModel, self).__init__(*args, **kwargs)
-
- self.controller = controller
- self.checkstates = {}
- self.group_items = {}
- self.plugin_items = {}
-
- def reset(self):
- self.group_items = {}
- self.plugin_items = {}
- self.clear()
-
- def append(self, plugin):
- plugin_groups = self.controller.order_groups.groups
- label = None
- order = None
- for _order, item in reversed(plugin_groups.items()):
- if _order is None or plugin.order < _order:
- label = item["label"]
- order = _order
- else:
- break
-
- if label is None:
- label = "Other"
-
- group_item = self.group_items.get(label)
- if not group_item:
- group_item = GroupItem(label, order=order)
- self.appendRow(group_item)
- self.group_items[label] = group_item
-
- new_item = PluginItem(plugin)
- group_item.appendRow(new_item)
-
- self.plugin_items[plugin._id] = new_item
-
- def store_checkstates(self):
- self.checkstates.clear()
-
- for plugin_item in self.plugin_items.values():
- if not plugin_item.plugin.optional:
- continue
-
- uid = plugin_item.data(Roles.ObjectUIdRole)
- self.checkstates[uid] = plugin_item.data(QtCore.Qt.CheckStateRole)
-
- def restore_checkstates(self):
- for plugin_item in self.plugin_items.values():
- if not plugin_item.plugin.optional:
- continue
-
- uid = plugin_item.data(Roles.ObjectUIdRole)
- state = self.checkstates.get(uid)
- if state is not None:
- plugin_item.setData(state, QtCore.Qt.CheckStateRole)
-
- def update_with_result(self, result):
- plugin = result["plugin"]
- item = self.plugin_items[plugin.id]
-
- new_flag_states = {
- PluginStates.InProgress: False,
- PluginStates.WasProcessed: True
- }
-
- publish_states = item.data(Roles.PublishFlagsRole)
-
- has_warning = publish_states & PluginStates.HasWarning
- new_records = result.get("records") or []
- if not has_warning:
- for record in new_records:
- level_no = record.get("levelno")
- if level_no and level_no >= 30:
- new_flag_states[PluginStates.HasWarning] = True
- break
-
- if (
- not publish_states & PluginStates.HasError
- and not result["success"]
- ):
- new_flag_states[PluginStates.HasError] = True
-
- if not publish_states & PluginStates.IsCompatible:
- new_flag_states[PluginStates.IsCompatible] = True
-
- item.setData(new_flag_states, Roles.PublishFlagsRole)
-
- records = item.data(Roles.LogRecordsRole) or []
- records.extend(new_records)
-
- item.setData(records, Roles.LogRecordsRole)
-
- return item
-
- def update_compatibility(self):
- context = self.controller.context
-
- families = util.collect_families_from_instances(context, True)
- for plugin_item in self.plugin_items.values():
- publish_states = plugin_item.data(Roles.PublishFlagsRole)
- if (
- publish_states & PluginStates.WasProcessed
- or publish_states & PluginStates.WasSkipped
- ):
- continue
-
- is_compatible = False
- # A plugin should always show if it has processed.
- if plugin_item.plugin.__instanceEnabled__:
- compatible_instances = pyblish.logic.instances_by_plugin(
- context, plugin_item.plugin
- )
- for instance in context:
- if not instance.data.get("publish"):
- continue
-
- if instance in compatible_instances:
- is_compatible = True
- break
- else:
- plugins = pyblish.logic.plugins_by_families(
- [plugin_item.plugin], families
- )
- if plugins:
- is_compatible = True
-
- current_is_compatible = publish_states & PluginStates.IsCompatible
- if (
- (is_compatible and not current_is_compatible)
- or (not is_compatible and current_is_compatible)
- ):
- new_flag = {
- PluginStates.IsCompatible: is_compatible
- }
- plugin_item.setData(new_flag, Roles.PublishFlagsRole)
-
-
-class PluginFilterProxy(QtCore.QSortFilterProxyModel):
- def filterAcceptsRow(self, source_row, source_parent):
- index = self.sourceModel().index(source_row, 0, source_parent)
- item_type = index.data(Roles.TypeRole)
- if item_type != PluginType:
- return True
-
- publish_states = index.data(Roles.PublishFlagsRole)
- if (
- publish_states & PluginStates.WasSkipped
- or not publish_states & PluginStates.IsCompatible
- ):
- return False
- return True
-
-
-class InstanceItem(QtGui.QStandardItem):
- """Instance item implementation."""
-
- def __init__(self, instance):
- super(InstanceItem, self).__init__()
-
- self.instance = instance
- self.is_context = False
- publish_states = getattr(instance, "_publish_states", 0)
- if publish_states & InstanceStates.ContextType:
- self.is_context = True
-
- instance._publish_states = publish_states
- instance._logs = []
- instance.optional = getattr(instance, "optional", True)
- instance.data["publish"] = instance.data.get("publish", True)
-
- family = self.data(Roles.FamiliesRole)[0]
- self.setData(
- "{}.{}".format(family, self.instance.data["name"]),
- Roles.ObjectUIdRole
- )
-
- def flags(self):
- return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
-
- def type(self):
- return InstanceType
-
- def data(self, role=QtCore.Qt.DisplayRole):
- if role == QtCore.Qt.DisplayRole:
- label = None
- if settings.UseLabel:
- label = self.instance.data.get("label")
-
- if not label:
- if self.is_context:
- label = "Context"
- else:
- label = self.instance.data["name"]
- return label
-
- if role == QtCore.Qt.DecorationRole:
- icon_name = self.instance.data.get("icon") or "file"
- return QAwesomeTextIconFactory.icon(icon_name)
-
- if role == Roles.TypeRole:
- return self.type()
-
- if role == Roles.ObjectIdRole:
- return self.instance.id
-
- if role == Roles.FamiliesRole:
- if self.is_context:
- return ["Context"]
-
- families = []
- family = self.instance.data.get("family")
- if family:
- families.append(family)
-
- _families = self.instance.data.get("families") or []
- for _family in _families:
- if _family not in families:
- families.append(_family)
-
- return families
-
- if role == Roles.IsOptionalRole:
- return self.instance.optional
-
- if role == QtCore.Qt.CheckStateRole:
- return self.instance.data["publish"]
-
- if role == Roles.PublishFlagsRole:
- return self.instance._publish_states
-
- if role == Roles.LogRecordsRole:
- return self.instance._logs
-
- return super(InstanceItem, self).data(role)
-
- def setData(self, value, role=(QtCore.Qt.UserRole + 1)):
- if role == QtCore.Qt.CheckStateRole:
- if not self.data(Roles.IsEnabledRole):
- return
- self.instance.data["publish"] = value
- self.emitDataChanged()
- return
-
- if role == Roles.IsEnabledRole:
- if not self.instance.optional:
- return
-
- if role == Roles.PublishFlagsRole:
- if isinstance(value, list):
- _value = self.instance._publish_states
- for flag in value:
- _value |= flag
- value = _value
-
- elif isinstance(value, dict):
- _value = self.instance._publish_states
- for flag, _bool in value.items():
- if _bool is True:
- _value |= flag
- elif _value & flag:
- _value ^= flag
- value = _value
-
- if value & InstanceStates.HasWarning:
- if self.parent():
- self.parent().setData(
- {GroupStates.HasWarning: True},
- Roles.PublishFlagsRole
- )
- if value & InstanceStates.HasError:
- if self.parent():
- self.parent().setData(
- {GroupStates.HasError: True},
- Roles.PublishFlagsRole
- )
-
- self.instance._publish_states = value
- self.emitDataChanged()
- return
-
- if role == Roles.LogRecordsRole:
- self.instance._logs = value
- self.emitDataChanged()
- return
-
- return super(InstanceItem, self).setData(value, role)
-
-
-class InstanceModel(QtGui.QStandardItemModel):
-
- group_created = QtCore.Signal(QtCore.QModelIndex)
-
- def __init__(self, controller, *args, **kwargs):
- super(InstanceModel, self).__init__(*args, **kwargs)
-
- self.controller = controller
- self.checkstates = {}
- self.group_items = {}
- self.instance_items = {}
-
- def reset(self):
- self.group_items = {}
- self.instance_items = {}
- self.clear()
-
- def append(self, instance):
- new_item = InstanceItem(instance)
- if new_item.is_context:
- self.appendRow(new_item)
- else:
- families = new_item.data(Roles.FamiliesRole)
- group_item = self.group_items.get(families[0])
- if not group_item:
- group_item = GroupItem(families[0])
- self.appendRow(group_item)
- self.group_items[families[0]] = group_item
- self.group_created.emit(group_item.index())
-
- group_item.appendRow(new_item)
- instance_id = instance.id
- self.instance_items[instance_id] = new_item
-
- def remove(self, instance_id):
- instance_item = self.instance_items.pop(instance_id)
- parent_item = instance_item.parent()
- parent_item.removeRow(instance_item.row())
- if parent_item.rowCount():
- return
-
- self.group_items.pop(parent_item.data(QtCore.Qt.DisplayRole))
- self.removeRow(parent_item.row())
-
- def store_checkstates(self):
- self.checkstates.clear()
-
- for instance_item in self.instance_items.values():
- if not instance_item.instance.optional:
- continue
-
- uid = instance_item.data(Roles.ObjectUIdRole)
- self.checkstates[uid] = instance_item.data(
- QtCore.Qt.CheckStateRole
- )
-
- def restore_checkstates(self):
- for instance_item in self.instance_items.values():
- if not instance_item.instance.optional:
- continue
-
- uid = instance_item.data(Roles.ObjectUIdRole)
- state = self.checkstates.get(uid)
- if state is not None:
- instance_item.setData(state, QtCore.Qt.CheckStateRole)
-
- def update_with_result(self, result):
- instance = result["instance"]
- if instance is None:
- instance_id = self.controller.context.id
- else:
- instance_id = instance.id
-
- item = self.instance_items.get(instance_id)
- if not item:
- return
-
- new_flag_states = {
- InstanceStates.InProgress: False
- }
-
- publish_states = item.data(Roles.PublishFlagsRole)
- has_warning = publish_states & InstanceStates.HasWarning
- new_records = result.get("records") or []
- if not has_warning:
- for record in new_records:
- level_no = record.get("levelno")
- if level_no and level_no >= 30:
- new_flag_states[InstanceStates.HasWarning] = True
- break
-
- if (
- not publish_states & InstanceStates.HasError
- and not result["success"]
- ):
- new_flag_states[InstanceStates.HasError] = True
-
- item.setData(new_flag_states, Roles.PublishFlagsRole)
-
- records = item.data(Roles.LogRecordsRole) or []
- records.extend(new_records)
-
- item.setData(records, Roles.LogRecordsRole)
-
- return item
-
- def update_compatibility(self, context, instances):
- families = util.collect_families_from_instances(context, True)
- for plugin_item in self.plugin_items.values():
- publish_states = plugin_item.data(Roles.PublishFlagsRole)
- if (
- publish_states & PluginStates.WasProcessed
- or publish_states & PluginStates.WasSkipped
- ):
- continue
-
- is_compatible = False
- # A plugin should always show if it has processed.
- if plugin_item.plugin.__instanceEnabled__:
- compatibleInstances = pyblish.logic.instances_by_plugin(
- context, plugin_item.plugin
- )
- for instance in instances:
- if not instance.data.get("publish"):
- continue
-
- if instance in compatibleInstances:
- is_compatible = True
- break
- else:
- plugins = pyblish.logic.plugins_by_families(
- [plugin_item.plugin], families
- )
- if plugins:
- is_compatible = True
-
- current_is_compatible = publish_states & PluginStates.IsCompatible
- if (
- (is_compatible and not current_is_compatible)
- or (not is_compatible and current_is_compatible)
- ):
- plugin_item.setData(
- {PluginStates.IsCompatible: is_compatible},
- Roles.PublishFlagsRole
- )
-
-
-class InstanceSortProxy(QtCore.QSortFilterProxyModel):
- def __init__(self, *args, **kwargs):
- super(InstanceSortProxy, self).__init__(*args, **kwargs)
- # Do not care about lower/upper case
- self.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
-
- def lessThan(self, x_index, y_index):
- x_type = x_index.data(Roles.TypeRole)
- y_type = y_index.data(Roles.TypeRole)
- if x_type != y_type:
- if x_type == GroupType:
- return False
- return True
- return super(InstanceSortProxy, self).lessThan(x_index, y_index)
-
-
-class TerminalDetailItem(QtGui.QStandardItem):
- key_label_record_map = (
- ("instance", "Instance"),
- ("msg", "Message"),
- ("name", "Plugin"),
- ("pathname", "Path"),
- ("lineno", "Line"),
- ("traceback", "Traceback"),
- ("levelname", "Level"),
- ("threadName", "Thread"),
- ("msecs", "Millis")
- )
-
- def __init__(self, record_item):
- self.record_item = record_item
- self.msg = None
- msg = record_item.get("msg")
- if msg is None:
- msg = record_item["label"].split("\n")[0]
-
- super(TerminalDetailItem, self).__init__(msg)
-
- def data(self, role=QtCore.Qt.DisplayRole):
- if role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
- if self.msg is None:
- self.msg = self.compute_detail_text(self.record_item)
- return self.msg
- return super(TerminalDetailItem, self).data(role)
-
- def compute_detail_text(self, item_data):
- if item_data["type"] == "info":
- return item_data["label"]
-
- html_text = ""
- for key, title in self.key_label_record_map:
- if key not in item_data:
- continue
- value = item_data[key]
- text = (
- str(value)
- .replace("<", "<")
- .replace(">", ">")
- .replace('\n', '
')
- .replace(' ', ' ')
- )
-
- title_tag = (
- '{}: '
- ' color:#fff;\" >{}: '
- ).format(title)
-
- html_text += (
- '
| {} |
'
- '| {} |
'
- ).format(title_tag, text)
-
- html_text = ''.format(
- html_text
- )
- return html_text
-
-
-class TerminalModel(QtGui.QStandardItemModel):
- item_icon_name = {
- "info": "fa.info",
- "record": "fa.circle",
- "error": "fa.exclamation-triangle",
- }
-
- item_icon_colors = {
- "info": "#ffffff",
- "error": "#ff4a4a",
- "log_debug": "#ff66e8",
- "log_info": "#66abff",
- "log_warning": "#ffba66",
- "log_error": "#ff4d58",
- "log_critical": "#ff4f75",
- None: "#333333"
- }
-
- level_to_record = (
- (10, "log_debug"),
- (20, "log_info"),
- (30, "log_warning"),
- (40, "log_error"),
- (50, "log_critical")
-
- )
-
- def __init__(self, *args, **kwargs):
- super(TerminalModel, self).__init__(*args, **kwargs)
- self.reset()
-
- def reset(self):
- self.clear()
-
- def prepare_records(self, result, suspend_logs):
- prepared_records = []
- instance_name = None
- instance = result["instance"]
- if instance is not None:
- instance_name = instance.data["name"]
-
- if not suspend_logs:
- for record in result.get("records") or []:
- if isinstance(record, dict):
- record_item = record
- else:
- record_item = {
- "label": str(record.msg),
- "type": "record",
- "levelno": record.levelno,
- "threadName": record.threadName,
- "name": record.name,
- "filename": record.filename,
- "pathname": record.pathname,
- "lineno": record.lineno,
- "msg": str(record.msg),
- "msecs": record.msecs,
- "levelname": record.levelname
- }
-
- if instance_name is not None:
- record_item["instance"] = instance_name
-
- prepared_records.append(record_item)
-
- error = result.get("error")
- if error:
- fname, line_no, func, exc = error.traceback
- error_item = {
- "label": str(error),
- "type": "error",
- "filename": str(fname),
- "lineno": str(line_no),
- "func": str(func),
- "traceback": error.formatted_traceback,
- }
-
- if instance_name is not None:
- error_item["instance"] = instance_name
-
- prepared_records.append(error_item)
-
- return prepared_records
-
- def append(self, record_items):
- all_record_items = []
- for record_item in record_items:
- record_type = record_item["type"]
- # Add error message to detail
- if record_type == "error":
- record_item["msg"] = record_item["label"]
- terminal_item_type = None
- if record_type == "record":
- for level, _type in self.level_to_record:
- if level > record_item["levelno"]:
- break
- terminal_item_type = _type
-
- else:
- terminal_item_type = record_type
-
- icon_color = self.item_icon_colors.get(terminal_item_type)
- icon_name = self.item_icon_name.get(record_type)
-
- top_item_icon = None
- if icon_color and icon_name:
- top_item_icon = QAwesomeIconFactory.icon(icon_name, icon_color)
-
- label = record_item["label"].split("\n")[0]
-
- top_item = QtGui.QStandardItem()
- all_record_items.append(top_item)
-
- detail_item = TerminalDetailItem(record_item)
- top_item.appendRow(detail_item)
-
- top_item.setData(TerminalLabelType, Roles.TypeRole)
- top_item.setData(terminal_item_type, Roles.TerminalItemTypeRole)
- top_item.setData(label, QtCore.Qt.DisplayRole)
- top_item.setFlags(
- QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
- )
-
- if top_item_icon:
- top_item.setData(top_item_icon, QtCore.Qt.DecorationRole)
-
- detail_item.setData(TerminalDetailType, Roles.TypeRole)
-
- self.invisibleRootItem().appendRows(all_record_items)
-
- def update_with_result(self, result):
- self.append(result["records"])
-
-
-class TerminalProxy(QtCore.QSortFilterProxyModel):
- filter_buttons_checks = {
- "info": settings.TerminalFilters.get("info", True),
- "log_debug": settings.TerminalFilters.get("log_debug", True),
- "log_info": settings.TerminalFilters.get("log_info", True),
- "log_warning": settings.TerminalFilters.get("log_warning", True),
- "log_error": settings.TerminalFilters.get("log_error", True),
- "log_critical": settings.TerminalFilters.get("log_critical", True),
- "error": settings.TerminalFilters.get("error", True)
- }
-
- instances = []
-
- def __init__(self, view, *args, **kwargs):
- super(self.__class__, self).__init__(*args, **kwargs)
- self.__class__.instances.append(self)
- # Store parent because by own `QSortFilterProxyModel` has `parent`
- # method not returning parent QObject in PySide and PyQt4
- self.view = view
-
- @classmethod
- def change_filter(cls, name, value):
- cls.filter_buttons_checks[name] = value
-
- for instance in cls.instances:
- try:
- instance.invalidate()
- if instance.view:
- instance.view.updateGeometry()
-
- except RuntimeError:
- # C++ Object was deleted
- cls.instances.remove(instance)
-
- def filterAcceptsRow(self, source_row, source_parent):
- index = self.sourceModel().index(source_row, 0, source_parent)
- item_type = index.data(Roles.TypeRole)
- if not item_type == TerminalLabelType:
- return True
- terminal_item_type = index.data(Roles.TerminalItemTypeRole)
- return self.__class__.filter_buttons_checks.get(
- terminal_item_type, True
- )
diff --git a/client/ayon_core/tools/pyblish_pype/settings.py b/client/ayon_core/tools/pyblish_pype/settings.py
deleted file mode 100644
index 5b69eb6a50..0000000000
--- a/client/ayon_core/tools/pyblish_pype/settings.py
+++ /dev/null
@@ -1,30 +0,0 @@
-from .util import env_variable_to_bool
-
-# Customize the window of the pyblish-lite window.
-WindowTitle = "Pyblish"
-
-# Customize whether to show label names for plugins.
-UseLabel = True
-
-# Customize which tab to start on. Possible choices are: "artist", "overview"
-# and "terminal".
-InitialTab = "overview"
-
-# Customize the window size.
-WindowSize = (430, 600)
-
-TerminalFilters = {
- "info": True,
- "log_debug": True,
- "log_info": True,
- "log_warning": True,
- "log_error": True,
- "log_critical": True,
- "traceback": True,
-}
-
-# Allow animations in GUI
-Animated = env_variable_to_bool("AYON_PYBLISH_ANIMATED", True)
-
-# Print UI info message to console
-PrintInfo = env_variable_to_bool("AYON_PYBLISH_PRINT_INFO", True)
diff --git a/client/ayon_core/tools/pyblish_pype/util.py b/client/ayon_core/tools/pyblish_pype/util.py
deleted file mode 100644
index 081f7775d5..0000000000
--- a/client/ayon_core/tools/pyblish_pype/util.py
+++ /dev/null
@@ -1,144 +0,0 @@
-from __future__ import (
- absolute_import,
- division,
- print_function,
- unicode_literals
-)
-
-import os
-import sys
-import collections
-
-from qtpy import QtCore
-import pyblish.api
-
-root = os.path.dirname(__file__)
-
-
-def get_asset(*path):
- """Return path to asset, relative the install directory
-
- Usage:
- >>> path = get_asset("dir", "to", "asset.png")
- >>> path == os.path.join(root, "dir", "to", "asset.png")
- True
-
- Arguments:
- path (str): One or more paths, to be concatenated
-
- """
-
- return os.path.join(root, *path)
-
-
-def defer(delay, func):
- """Append artificial delay to `func`
-
- This aids in keeping the GUI responsive, but complicates logic
- when producing tests. To combat this, the environment variable ensures
- that every operation is synchronous.
-
- Arguments:
- delay (float): Delay multiplier; default 1, 0 means no delay
- func (callable): Any callable
-
- """
-
- delay *= float(os.getenv("PYBLISH_DELAY", 1))
- if delay > 0:
- return QtCore.QTimer.singleShot(delay, func)
- else:
- return func()
-
-
-def u_print(msg, **kwargs):
- """`print` with encoded unicode.
-
- `print` unicode may cause UnicodeEncodeError
- or non-readable result when `PYTHONIOENCODING` is not set.
- this will fix it.
-
- Arguments:
- msg (unicode): Message to print.
- **kwargs: Keyword argument for `print` function.
- """
-
- if isinstance(msg, str):
- encoding = None
- try:
- encoding = os.getenv('PYTHONIOENCODING', sys.stdout.encoding)
- except AttributeError:
- # `sys.stdout.encoding` may not exists.
- pass
- msg = msg.encode(encoding or 'utf-8', 'replace')
- print(msg, **kwargs)
-
-
-def collect_families_from_instances(instances, only_active=False):
- all_families = set()
- for instance in instances:
- if only_active:
- if instance.data.get("publish") is False:
- continue
- family = instance.data.get("family")
- if family:
- all_families.add(family)
-
- families = instance.data.get("families") or tuple()
- for family in families:
- all_families.add(family)
-
- return list(all_families)
-
-
-class OrderGroups:
- validation_order = pyblish.api.ValidatorOrder + 0.5
- groups = collections.OrderedDict((
- (
- pyblish.api.CollectorOrder + 0.5,
- {
- "label": "Collect",
- "state": "Collecting.."
- }
- ),
- (
- pyblish.api.ValidatorOrder + 0.5,
- {
- "label": "Validate",
- "state": "Validating.."
- }
- ),
- (
- pyblish.api.ExtractorOrder + 0.5,
- {
- "label": "Extract",
- "state": "Extracting.."
- }
- ),
- (
- pyblish.api.IntegratorOrder + 0.5,
- {
- "label": "Integrate",
- "state": "Integrating.."
- }
- ),
- (
- None,
- {
- "label": "Other",
- "state": "Finishing.."
- }
- )
- ))
-
-
-def env_variable_to_bool(env_key, default=False):
- """Boolean based on environment variable value."""
- value = os.environ.get(env_key)
- if value is not None:
- value = value.lower()
- if value in ("true", "1", "yes", "on"):
- return True
- elif value in ("false", "0", "no", "off"):
- return False
- return default
diff --git a/client/ayon_core/tools/pyblish_pype/vendor/__init__.py b/client/ayon_core/tools/pyblish_pype/vendor/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/__init__.py b/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/__init__.py
deleted file mode 100644
index 4a0001ebb7..0000000000
--- a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/__init__.py
+++ /dev/null
@@ -1,39 +0,0 @@
-"""
-qtawesome - use font-awesome in PyQt / PySide applications
-
-This is a port to Python of the C++ QtAwesome library by Rick Blommers
-"""
-from .iconic_font import IconicFont, set_global_defaults
-from .animation import Pulse, Spin
-from ._version import version_info, __version__
-
-_resource = {'iconic': None, }
-
-
-def _instance():
- if _resource['iconic'] is None:
- _resource['iconic'] = IconicFont(('fa', 'fontawesome-webfont.ttf', 'fontawesome-webfont-charmap.json'),
- ('ei', 'elusiveicons-webfont.ttf', 'elusiveicons-webfont-charmap.json'))
- return _resource['iconic']
-
-
-def icon(*args, **kwargs):
- return _instance().icon(*args, **kwargs)
-
-
-def load_font(*args, **kwargs):
- return _instance().load_font(*args, **kwargs)
-
-
-def charmap(prefixed_name):
- prefix, name = prefixed_name.split('.')
- return _instance().charmap[prefix][name]
-
-
-def font(*args, **kwargs):
- return _instance().font(*args, **kwargs)
-
-
-def set_defaults(**kwargs):
- return set_global_defaults(**kwargs)
-
diff --git a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/_version.py b/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/_version.py
deleted file mode 100644
index 7af886d1a0..0000000000
--- a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/_version.py
+++ /dev/null
@@ -1,2 +0,0 @@
-version_info = (0, 3, 0, 'dev')
-__version__ = '.'.join(map(str, version_info))
diff --git a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/animation.py b/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/animation.py
deleted file mode 100644
index ac69507444..0000000000
--- a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/animation.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from qtpy import QtCore
-
-
-class Spin:
-
- def __init__(self, parent_widget, interval=10, step=1):
- self.parent_widget = parent_widget
- self.interval, self.step = interval, step
- self.info = {}
-
- def _update(self, parent_widget):
- if self.parent_widget in self.info:
- timer, angle, step = self.info[self.parent_widget]
-
- if angle >= 360:
- angle = 0
-
- angle += step
- self.info[parent_widget] = timer, angle, step
- parent_widget.update()
-
- def setup(self, icon_painter, painter, rect):
-
- if self.parent_widget not in self.info:
- timer = QtCore.QTimer()
- timer.timeout.connect(lambda: self._update(self.parent_widget))
- self.info[self.parent_widget] = [timer, 0, self.step]
- timer.start(self.interval)
- else:
- timer, angle, self.step = self.info[self.parent_widget]
- x_center = rect.width() * 0.5
- y_center = rect.height() * 0.5
- painter.translate(x_center, y_center)
- painter.rotate(angle)
- painter.translate(-x_center, -y_center)
-
-
-class Pulse(Spin):
-
- def __init__(self, parent_widget):
- Spin.__init__(self, parent_widget, interval=300, step=45)
diff --git a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/elusiveicons-webfont-charmap.json b/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/elusiveicons-webfont-charmap.json
deleted file mode 100644
index 099bcb818c..0000000000
--- a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/elusiveicons-webfont-charmap.json
+++ /dev/null
@@ -1,306 +0,0 @@
-{
- "address-book": "0xf102",
- "address-book-alt": "0xf101",
- "adjust": "0xf104",
- "adjust-alt": "0xf103",
- "adult": "0xf105",
- "align-center": "0xf106",
- "align-justify": "0xf107",
- "align-left": "0xf108",
- "align-right": "0xf109",
- "arrow-down": "0xf10a",
- "arrow-left": "0xf10b",
- "arrow-right": "0xf10c",
- "arrow-up": "0xf10d",
- "asl": "0xf10e",
- "asterisk": "0xf10f",
- "backward": "0xf110",
- "ban-circle": "0xf111",
- "barcode": "0xf112",
- "behance": "0xf113",
- "bell": "0xf114",
- "blind": "0xf115",
- "blogger": "0xf116",
- "bold": "0xf117",
- "book": "0xf118",
- "bookmark": "0xf11a",
- "bookmark-empty": "0xf119",
- "braille": "0xf11b",
- "briefcase": "0xf11c",
- "broom": "0xf11d",
- "brush": "0xf11e",
- "bulb": "0xf11f",
- "bullhorn": "0xf120",
- "calendar": "0xf122",
- "calendar-sign": "0xf121",
- "camera": "0xf123",
- "car": "0xf124",
- "caret-down": "0xf125",
- "caret-left": "0xf126",
- "caret-right": "0xf127",
- "caret-up": "0xf128",
- "cc": "0xf129",
- "certificate": "0xf12a",
- "check": "0xf12c",
- "check-empty": "0xf12b",
- "chevron-down": "0xf12d",
- "chevron-left": "0xf12e",
- "chevron-right": "0xf12f",
- "chevron-up": "0xf130",
- "child": "0xf131",
- "circle-arrow-down": "0xf132",
- "circle-arrow-left": "0xf133",
- "circle-arrow-right": "0xf134",
- "circle-arrow-up": "0xf135",
- "cloud": "0xf137",
- "cloud-alt": "0xf136",
- "cog": "0xf139",
- "cog-alt": "0xf138",
- "cogs": "0xf13a",
- "comment": "0xf13c",
- "comment-alt": "0xf13b",
- "compass": "0xf13e",
- "compass-alt": "0xf13d",
- "credit-card": "0xf13f",
- "css": "0xf140",
- "dashboard": "0xf141",
- "delicious": "0xf142",
- "deviantart": "0xf143",
- "digg": "0xf144",
- "download": "0xf146",
- "download-alt": "0xf145",
- "dribbble": "0xf147",
- "edit": "0xf148",
- "eject": "0xf149",
- "envelope": "0xf14b",
- "envelope-alt": "0xf14a",
- "error": "0xf14d",
- "error-alt": "0xf14c",
- "eur": "0xf14e",
- "exclamation-sign": "0xf14f",
- "eye-close": "0xf150",
- "eye-open": "0xf151",
- "facebook": "0xf152",
- "facetime-video": "0xf153",
- "fast-backward": "0xf154",
- "fast-forward": "0xf155",
- "female": "0xf156",
- "file": "0xf15c",
- "file-alt": "0xf157",
- "file-edit": "0xf159",
- "file-edit-alt": "0xf158",
- "file-new": "0xf15b",
- "file-new-alt": "0xf15a",
- "film": "0xf15d",
- "filter": "0xf15e",
- "fire": "0xf15f",
- "flag": "0xf161",
- "flag-alt": "0xf160",
- "flickr": "0xf162",
- "folder": "0xf166",
- "folder-close": "0xf163",
- "folder-open": "0xf164",
- "folder-sign": "0xf165",
- "font": "0xf167",
- "fontsize": "0xf168",
- "fork": "0xf169",
- "forward": "0xf16b",
- "forward-alt": "0xf16a",
- "foursquare": "0xf16c",
- "friendfeed": "0xf16e",
- "friendfeed-rect": "0xf16d",
- "fullscreen": "0xf16f",
- "gbp": "0xf170",
- "gift": "0xf171",
- "github": "0xf173",
- "github-text": "0xf172",
- "glass": "0xf174",
- "glasses": "0xf175",
- "globe": "0xf177",
- "globe-alt": "0xf176",
- "googleplus": "0xf178",
- "graph": "0xf17a",
- "graph-alt": "0xf179",
- "group": "0xf17c",
- "group-alt": "0xf17b",
- "guidedog": "0xf17d",
- "hand-down": "0xf17e",
- "hand-left": "0xf17f",
- "hand-right": "0xf180",
- "hand-up": "0xf181",
- "hdd": "0xf182",
- "headphones": "0xf183",
- "hearing-impaired": "0xf184",
- "heart": "0xf187",
- "heart-alt": "0xf185",
- "heart-empty": "0xf186",
- "home": "0xf189",
- "home-alt": "0xf188",
- "hourglass": "0xf18a",
- "idea": "0xf18c",
- "idea-alt": "0xf18b",
- "inbox": "0xf18f",
- "inbox-alt": "0xf18d",
- "inbox-box": "0xf18e",
- "indent-left": "0xf190",
- "indent-right": "0xf191",
- "info-circle": "0xf192",
- "instagram": "0xf193",
- "iphone-home": "0xf194",
- "italic": "0xf195",
- "key": "0xf196",
- "laptop": "0xf198",
- "laptop-alt": "0xf197",
- "lastfm": "0xf199",
- "leaf": "0xf19a",
- "lines": "0xf19b",
- "link": "0xf19c",
- "linkedin": "0xf19d",
- "list": "0xf19f",
- "list-alt": "0xf19e",
- "livejournal": "0xf1a0",
- "lock": "0xf1a2",
- "lock-alt": "0xf1a1",
- "magic": "0xf1a3",
- "magnet": "0xf1a4",
- "male": "0xf1a5",
- "map-marker": "0xf1a7",
- "map-marker-alt": "0xf1a6",
- "mic": "0xf1a9",
- "mic-alt": "0xf1a8",
- "minus": "0xf1ab",
- "minus-sign": "0xf1aa",
- "move": "0xf1ac",
- "music": "0xf1ad",
- "myspace": "0xf1ae",
- "network": "0xf1af",
- "off": "0xf1b0",
- "ok": "0xf1b3",
- "ok-circle": "0xf1b1",
- "ok-sign": "0xf1b2",
- "opensource": "0xf1b4",
- "paper-clip": "0xf1b6",
- "paper-clip-alt": "0xf1b5",
- "path": "0xf1b7",
- "pause": "0xf1b9",
- "pause-alt": "0xf1b8",
- "pencil": "0xf1bb",
- "pencil-alt": "0xf1ba",
- "person": "0xf1bc",
- "phone": "0xf1be",
- "phone-alt": "0xf1bd",
- "photo": "0xf1c0",
- "photo-alt": "0xf1bf",
- "picasa": "0xf1c1",
- "picture": "0xf1c2",
- "pinterest": "0xf1c3",
- "plane": "0xf1c4",
- "play": "0xf1c7",
- "play-alt": "0xf1c5",
- "play-circle": "0xf1c6",
- "plurk": "0xf1c9",
- "plurk-alt": "0xf1c8",
- "plus": "0xf1cb",
- "plus-sign": "0xf1ca",
- "podcast": "0xf1cc",
- "print": "0xf1cd",
- "puzzle": "0xf1ce",
- "qrcode": "0xf1cf",
- "question": "0xf1d1",
- "question-sign": "0xf1d0",
- "quote-alt": "0xf1d2",
- "quote-right": "0xf1d4",
- "quote-right-alt": "0xf1d3",
- "quotes": "0xf1d5",
- "random": "0xf1d6",
- "record": "0xf1d7",
- "reddit": "0xf1d8",
- "redux": "0xf1d9",
- "refresh": "0xf1da",
- "remove": "0xf1dd",
- "remove-circle": "0xf1db",
- "remove-sign": "0xf1dc",
- "repeat": "0xf1df",
- "repeat-alt": "0xf1de",
- "resize-full": "0xf1e0",
- "resize-horizontal": "0xf1e1",
- "resize-small": "0xf1e2",
- "resize-vertical": "0xf1e3",
- "return-key": "0xf1e4",
- "retweet": "0xf1e5",
- "reverse-alt": "0xf1e6",
- "road": "0xf1e7",
- "rss": "0xf1e8",
- "scissors": "0xf1e9",
- "screen": "0xf1eb",
- "screen-alt": "0xf1ea",
- "screenshot": "0xf1ec",
- "search": "0xf1ee",
- "search-alt": "0xf1ed",
- "share": "0xf1f0",
- "share-alt": "0xf1ef",
- "shopping-cart": "0xf1f2",
- "shopping-cart-sign": "0xf1f1",
- "signal": "0xf1f3",
- "skype": "0xf1f4",
- "slideshare": "0xf1f5",
- "smiley": "0xf1f7",
- "smiley-alt": "0xf1f6",
- "soundcloud": "0xf1f8",
- "speaker": "0xf1f9",
- "spotify": "0xf1fa",
- "stackoverflow": "0xf1fb",
- "star": "0xf1fe",
- "star-alt": "0xf1fc",
- "star-empty": "0xf1fd",
- "step-backward": "0xf1ff",
- "step-forward": "0xf200",
- "stop": "0xf202",
- "stop-alt": "0xf201",
- "stumbleupon": "0xf203",
- "tag": "0xf204",
- "tags": "0xf205",
- "tasks": "0xf206",
- "text-height": "0xf207",
- "text-width": "0xf208",
- "th": "0xf20b",
- "th-large": "0xf209",
- "th-list": "0xf20a",
- "thumbs-down": "0xf20c",
- "thumbs-up": "0xf20d",
- "time": "0xf20f",
- "time-alt": "0xf20e",
- "tint": "0xf210",
- "torso": "0xf211",
- "trash": "0xf213",
- "trash-alt": "0xf212",
- "tumblr": "0xf214",
- "twitter": "0xf215",
- "universal-access": "0xf216",
- "unlock": "0xf218",
- "unlock-alt": "0xf217",
- "upload": "0xf219",
- "usd": "0xf21a",
- "user": "0xf21b",
- "viadeo": "0xf21c",
- "video": "0xf21f",
- "video-alt": "0xf21d",
- "video-chat": "0xf21e",
- "view-mode": "0xf220",
- "vimeo": "0xf221",
- "vkontakte": "0xf222",
- "volume-down": "0xf223",
- "volume-off": "0xf224",
- "volume-up": "0xf225",
- "w3c": "0xf226",
- "warning-sign": "0xf227",
- "website": "0xf229",
- "website-alt": "0xf228",
- "wheelchair": "0xf22a",
- "wordpress": "0xf22b",
- "wrench": "0xf22d",
- "wrench-alt": "0xf22c",
- "youtube": "0xf22e",
- "zoom-in": "0xf22f",
- "zoom-out": "0xf230"
-}
diff --git a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/elusiveicons-webfont.ttf b/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/elusiveicons-webfont.ttf
deleted file mode 100644
index b6fe85d4b2..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/elusiveicons-webfont.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/fontawesome-webfont-charmap.json b/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/fontawesome-webfont-charmap.json
deleted file mode 100644
index 0e97d031e6..0000000000
--- a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/fontawesome-webfont-charmap.json
+++ /dev/null
@@ -1,696 +0,0 @@
-{
- "500px": "f26e",
- "adjust": "f042",
- "adn": "f170",
- "align-center": "f037",
- "align-justify": "f039",
- "align-left": "f036",
- "align-right": "f038",
- "amazon": "f270",
- "ambulance": "f0f9",
- "anchor": "f13d",
- "android": "f17b",
- "angellist": "f209",
- "angle-double-down": "f103",
- "angle-double-left": "f100",
- "angle-double-right": "f101",
- "angle-double-up": "f102",
- "angle-down": "f107",
- "angle-left": "f104",
- "angle-right": "f105",
- "angle-up": "f106",
- "apple": "f179",
- "archive": "f187",
- "area-chart": "f1fe",
- "arrow-circle-down": "f0ab",
- "arrow-circle-left": "f0a8",
- "arrow-circle-o-down": "f01a",
- "arrow-circle-o-left": "f190",
- "arrow-circle-o-right": "f18e",
- "arrow-circle-o-up": "f01b",
- "arrow-circle-right": "f0a9",
- "arrow-circle-up": "f0aa",
- "arrow-down": "f063",
- "arrow-left": "f060",
- "arrow-right": "f061",
- "arrow-up": "f062",
- "arrows": "f047",
- "arrows-alt": "f0b2",
- "arrows-h": "f07e",
- "arrows-v": "f07d",
- "asterisk": "f069",
- "at": "f1fa",
- "automobile": "f1b9",
- "backward": "f04a",
- "balance-scale": "f24e",
- "ban": "f05e",
- "bank": "f19c",
- "bar-chart": "f080",
- "bar-chart-o": "f080",
- "barcode": "f02a",
- "bars": "f0c9",
- "battery-0": "f244",
- "battery-1": "f243",
- "battery-2": "f242",
- "battery-3": "f241",
- "battery-4": "f240",
- "battery-empty": "f244",
- "battery-full": "f240",
- "battery-half": "f242",
- "battery-quarter": "f243",
- "battery-three-quarters": "f241",
- "bed": "f236",
- "beer": "f0fc",
- "behance": "f1b4",
- "behance-square": "f1b5",
- "bell": "f0f3",
- "bell-o": "f0a2",
- "bell-slash": "f1f6",
- "bell-slash-o": "f1f7",
- "bicycle": "f206",
- "binoculars": "f1e5",
- "birthday-cake": "f1fd",
- "bitbucket": "f171",
- "bitbucket-square": "f172",
- "bitcoin": "f15a",
- "black-tie": "f27e",
- "bluetooth": "f293",
- "bluetooth-b": "f294",
- "bold": "f032",
- "bolt": "f0e7",
- "bomb": "f1e2",
- "book": "f02d",
- "bookmark": "f02e",
- "bookmark-o": "f097",
- "briefcase": "f0b1",
- "btc": "f15a",
- "bug": "f188",
- "building": "f1ad",
- "building-o": "f0f7",
- "bullhorn": "f0a1",
- "bullseye": "f140",
- "bus": "f207",
- "buysellads": "f20d",
- "cab": "f1ba",
- "calculator": "f1ec",
- "calendar": "f073",
- "calendar-check-o": "f274",
- "calendar-minus-o": "f272",
- "calendar-o": "f133",
- "calendar-plus-o": "f271",
- "calendar-times-o": "f273",
- "camera": "f030",
- "camera-retro": "f083",
- "car": "f1b9",
- "caret-down": "f0d7",
- "caret-left": "f0d9",
- "caret-right": "f0da",
- "caret-square-o-down": "f150",
- "caret-square-o-left": "f191",
- "caret-square-o-right": "f152",
- "caret-square-o-up": "f151",
- "caret-up": "f0d8",
- "cart-arrow-down": "f218",
- "cart-plus": "f217",
- "cc": "f20a",
- "cc-amex": "f1f3",
- "cc-diners-club": "f24c",
- "cc-discover": "f1f2",
- "cc-jcb": "f24b",
- "cc-mastercard": "f1f1",
- "cc-paypal": "f1f4",
- "cc-stripe": "f1f5",
- "cc-visa": "f1f0",
- "certificate": "f0a3",
- "chain": "f0c1",
- "chain-broken": "f127",
- "check": "f00c",
- "check-circle": "f058",
- "check-circle-o": "f05d",
- "check-square": "f14a",
- "check-square-o": "f046",
- "chevron-circle-down": "f13a",
- "chevron-circle-left": "f137",
- "chevron-circle-right": "f138",
- "chevron-circle-up": "f139",
- "chevron-down": "f078",
- "chevron-left": "f053",
- "chevron-right": "f054",
- "chevron-up": "f077",
- "child": "f1ae",
- "chrome": "f268",
- "circle": "f111",
- "circle-o": "f10c",
- "circle-o-notch": "f1ce",
- "circle-thin": "f1db",
- "clipboard": "f0ea",
- "clock-o": "f017",
- "clone": "f24d",
- "close": "f00d",
- "cloud": "f0c2",
- "cloud-download": "f0ed",
- "cloud-upload": "f0ee",
- "cny": "f157",
- "code": "f121",
- "code-fork": "f126",
- "codepen": "f1cb",
- "codiepie": "f284",
- "coffee": "f0f4",
- "cog": "f013",
- "cogs": "f085",
- "columns": "f0db",
- "comment": "f075",
- "comment-o": "f0e5",
- "commenting": "f27a",
- "commenting-o": "f27b",
- "comments": "f086",
- "comments-o": "f0e6",
- "compass": "f14e",
- "compress": "f066",
- "connectdevelop": "f20e",
- "contao": "f26d",
- "copy": "f0c5",
- "copyright": "f1f9",
- "creative-commons": "f25e",
- "credit-card": "f09d",
- "credit-card-alt": "f283",
- "crop": "f125",
- "crosshairs": "f05b",
- "css3": "f13c",
- "cube": "f1b2",
- "cubes": "f1b3",
- "cut": "f0c4",
- "cutlery": "f0f5",
- "dashboard": "f0e4",
- "dashcube": "f210",
- "database": "f1c0",
- "dedent": "f03b",
- "delicious": "f1a5",
- "desktop": "f108",
- "deviantart": "f1bd",
- "diamond": "f219",
- "digg": "f1a6",
- "dollar": "f155",
- "dot-circle-o": "f192",
- "download": "f019",
- "dribbble": "f17d",
- "dropbox": "f16b",
- "drupal": "f1a9",
- "edge": "f282",
- "edit": "f044",
- "eject": "f052",
- "ellipsis-h": "f141",
- "ellipsis-v": "f142",
- "empire": "f1d1",
- "envelope": "f0e0",
- "envelope-o": "f003",
- "envelope-square": "f199",
- "eraser": "f12d",
- "eur": "f153",
- "euro": "f153",
- "exchange": "f0ec",
- "exclamation": "f12a",
- "exclamation-circle": "f06a",
- "exclamation-triangle": "f071",
- "expand": "f065",
- "expeditedssl": "f23e",
- "external-link": "f08e",
- "external-link-square": "f14c",
- "eye": "f06e",
- "eye-slash": "f070",
- "eyedropper": "f1fb",
- "facebook": "f09a",
- "facebook-f": "f09a",
- "facebook-official": "f230",
- "facebook-square": "f082",
- "fast-backward": "f049",
- "fast-forward": "f050",
- "fax": "f1ac",
- "feed": "f09e",
- "female": "f182",
- "fighter-jet": "f0fb",
- "file": "f15b",
- "file-archive-o": "f1c6",
- "file-audio-o": "f1c7",
- "file-code-o": "f1c9",
- "file-excel-o": "f1c3",
- "file-image-o": "f1c5",
- "file-movie-o": "f1c8",
- "file-o": "f016",
- "file-pdf-o": "f1c1",
- "file-photo-o": "f1c5",
- "file-picture-o": "f1c5",
- "file-powerpoint-o": "f1c4",
- "file-sound-o": "f1c7",
- "file-text": "f15c",
- "file-text-o": "f0f6",
- "file-video-o": "f1c8",
- "file-word-o": "f1c2",
- "file-zip-o": "f1c6",
- "files-o": "f0c5",
- "film": "f008",
- "filter": "f0b0",
- "fire": "f06d",
- "fire-extinguisher": "f134",
- "firefox": "f269",
- "flag": "f024",
- "flag-checkered": "f11e",
- "flag-o": "f11d",
- "flash": "f0e7",
- "flask": "f0c3",
- "flickr": "f16e",
- "floppy-o": "f0c7",
- "folder": "f07b",
- "folder-o": "f114",
- "folder-open": "f07c",
- "folder-open-o": "f115",
- "font": "f031",
- "fonticons": "f280",
- "fort-awesome": "f286",
- "forumbee": "f211",
- "forward": "f04e",
- "foursquare": "f180",
- "frown-o": "f119",
- "futbol-o": "f1e3",
- "gamepad": "f11b",
- "gavel": "f0e3",
- "gbp": "f154",
- "ge": "f1d1",
- "gear": "f013",
- "gears": "f085",
- "genderless": "f22d",
- "get-pocket": "f265",
- "gg": "f260",
- "gg-circle": "f261",
- "gift": "f06b",
- "git": "f1d3",
- "git-square": "f1d2",
- "github": "f09b",
- "github-alt": "f113",
- "github-square": "f092",
- "gittip": "f184",
- "glass": "f000",
- "globe": "f0ac",
- "google": "f1a0",
- "google-plus": "f0d5",
- "google-plus-square": "f0d4",
- "google-wallet": "f1ee",
- "graduation-cap": "f19d",
- "gratipay": "f184",
- "group": "f0c0",
- "h-square": "f0fd",
- "hacker-news": "f1d4",
- "hand-grab-o": "f255",
- "hand-lizard-o": "f258",
- "hand-o-down": "f0a7",
- "hand-o-left": "f0a5",
- "hand-o-right": "f0a4",
- "hand-o-up": "f0a6",
- "hand-paper-o": "f256",
- "hand-peace-o": "f25b",
- "hand-pointer-o": "f25a",
- "hand-rock-o": "f255",
- "hand-scissors-o": "f257",
- "hand-spock-o": "f259",
- "hand-stop-o": "f256",
- "hashtag": "f292",
- "hdd-o": "f0a0",
- "header": "f1dc",
- "headphones": "f025",
- "heart": "f004",
- "heart-o": "f08a",
- "heartbeat": "f21e",
- "history": "f1da",
- "home": "f015",
- "hospital-o": "f0f8",
- "hotel": "f236",
- "hourglass": "f254",
- "hourglass-1": "f251",
- "hourglass-2": "f252",
- "hourglass-3": "f253",
- "hourglass-end": "f253",
- "hourglass-half": "f252",
- "hourglass-o": "f250",
- "hourglass-start": "f251",
- "houzz": "f27c",
- "html5": "f13b",
- "i-cursor": "f246",
- "ils": "f20b",
- "image": "f03e",
- "inbox": "f01c",
- "indent": "f03c",
- "industry": "f275",
- "info": "f129",
- "info-circle": "f05a",
- "inr": "f156",
- "instagram": "f16d",
- "institution": "f19c",
- "internet-explorer": "f26b",
- "intersex": "f224",
- "ioxhost": "f208",
- "italic": "f033",
- "joomla": "f1aa",
- "jpy": "f157",
- "jsfiddle": "f1cc",
- "key": "f084",
- "keyboard-o": "f11c",
- "krw": "f159",
- "language": "f1ab",
- "laptop": "f109",
- "lastfm": "f202",
- "lastfm-square": "f203",
- "leaf": "f06c",
- "leanpub": "f212",
- "legal": "f0e3",
- "lemon-o": "f094",
- "level-down": "f149",
- "level-up": "f148",
- "life-bouy": "f1cd",
- "life-buoy": "f1cd",
- "life-ring": "f1cd",
- "life-saver": "f1cd",
- "lightbulb-o": "f0eb",
- "line-chart": "f201",
- "link": "f0c1",
- "linkedin": "f0e1",
- "linkedin-square": "f08c",
- "linux": "f17c",
- "list": "f03a",
- "list-alt": "f022",
- "list-ol": "f0cb",
- "list-ul": "f0ca",
- "location-arrow": "f124",
- "lock": "f023",
- "long-arrow-down": "f175",
- "long-arrow-left": "f177",
- "long-arrow-right": "f178",
- "long-arrow-up": "f176",
- "magic": "f0d0",
- "magnet": "f076",
- "mail-forward": "f064",
- "mail-reply": "f112",
- "mail-reply-all": "f122",
- "male": "f183",
- "map": "f279",
- "map-marker": "f041",
- "map-o": "f278",
- "map-pin": "f276",
- "map-signs": "f277",
- "mars": "f222",
- "mars-double": "f227",
- "mars-stroke": "f229",
- "mars-stroke-h": "f22b",
- "mars-stroke-v": "f22a",
- "maxcdn": "f136",
- "meanpath": "f20c",
- "medium": "f23a",
- "medkit": "f0fa",
- "meh-o": "f11a",
- "mercury": "f223",
- "microphone": "f130",
- "microphone-slash": "f131",
- "minus": "f068",
- "minus-circle": "f056",
- "minus-square": "f146",
- "minus-square-o": "f147",
- "mixcloud": "f289",
- "mobile": "f10b",
- "mobile-phone": "f10b",
- "modx": "f285",
- "money": "f0d6",
- "moon-o": "f186",
- "mortar-board": "f19d",
- "motorcycle": "f21c",
- "mouse-pointer": "f245",
- "music": "f001",
- "navicon": "f0c9",
- "neuter": "f22c",
- "newspaper-o": "f1ea",
- "object-group": "f247",
- "object-ungroup": "f248",
- "odnoklassniki": "f263",
- "odnoklassniki-square": "f264",
- "opencart": "f23d",
- "openid": "f19b",
- "opera": "f26a",
- "optin-monster": "f23c",
- "outdent": "f03b",
- "pagelines": "f18c",
- "paint-brush": "f1fc",
- "paper-plane": "f1d8",
- "paper-plane-o": "f1d9",
- "paperclip": "f0c6",
- "paragraph": "f1dd",
- "paste": "f0ea",
- "pause": "f04c",
- "pause-circle": "f28b",
- "pause-circle-o": "f28c",
- "paw": "f1b0",
- "paypal": "f1ed",
- "pencil": "f040",
- "pencil-square": "f14b",
- "pencil-square-o": "f044",
- "percent": "f295",
- "phone": "f095",
- "phone-square": "f098",
- "photo": "f03e",
- "picture-o": "f03e",
- "pie-chart": "f200",
- "pied-piper": "f1a7",
- "pied-piper-alt": "f1a8",
- "pinterest": "f0d2",
- "pinterest-p": "f231",
- "pinterest-square": "f0d3",
- "plane": "f072",
- "play": "f04b",
- "play-circle": "f144",
- "play-circle-o": "f01d",
- "plug": "f1e6",
- "plus": "f067",
- "plus-circle": "f055",
- "plus-square": "f0fe",
- "plus-square-o": "f196",
- "power-off": "f011",
- "print": "f02f",
- "product-hunt": "f288",
- "puzzle-piece": "f12e",
- "qq": "f1d6",
- "qrcode": "f029",
- "question": "f128",
- "question-circle": "f059",
- "quote-left": "f10d",
- "quote-right": "f10e",
- "ra": "f1d0",
- "random": "f074",
- "rebel": "f1d0",
- "recycle": "f1b8",
- "reddit": "f1a1",
- "reddit-alien": "f281",
- "reddit-square": "f1a2",
- "refresh": "f021",
- "registered": "f25d",
- "remove": "f00d",
- "renren": "f18b",
- "reorder": "f0c9",
- "repeat": "f01e",
- "reply": "f112",
- "reply-all": "f122",
- "retweet": "f079",
- "rmb": "f157",
- "road": "f018",
- "rocket": "f135",
- "rotate-left": "f0e2",
- "rotate-right": "f01e",
- "rouble": "f158",
- "rss": "f09e",
- "rss-square": "f143",
- "rub": "f158",
- "ruble": "f158",
- "rupee": "f156",
- "safari": "f267",
- "save": "f0c7",
- "scissors": "f0c4",
- "scribd": "f28a",
- "search": "f002",
- "search-minus": "f010",
- "search-plus": "f00e",
- "sellsy": "f213",
- "send": "f1d8",
- "send-o": "f1d9",
- "server": "f233",
- "share": "f064",
- "share-alt": "f1e0",
- "share-alt-square": "f1e1",
- "share-square": "f14d",
- "share-square-o": "f045",
- "shekel": "f20b",
- "sheqel": "f20b",
- "shield": "f132",
- "ship": "f21a",
- "shirtsinbulk": "f214",
- "shopping-bag": "f290",
- "shopping-basket": "f291",
- "shopping-cart": "f07a",
- "sign-in": "f090",
- "sign-out": "f08b",
- "signal": "f012",
- "simplybuilt": "f215",
- "sitemap": "f0e8",
- "skyatlas": "f216",
- "skype": "f17e",
- "slack": "f198",
- "sliders": "f1de",
- "slideshare": "f1e7",
- "smile-o": "f118",
- "soccer-ball-o": "f1e3",
- "sort": "f0dc",
- "sort-alpha-asc": "f15d",
- "sort-alpha-desc": "f15e",
- "sort-amount-asc": "f160",
- "sort-amount-desc": "f161",
- "sort-asc": "f0de",
- "sort-desc": "f0dd",
- "sort-down": "f0dd",
- "sort-numeric-asc": "f162",
- "sort-numeric-desc": "f163",
- "sort-up": "f0de",
- "soundcloud": "f1be",
- "space-shuttle": "f197",
- "spinner": "f110",
- "spoon": "f1b1",
- "spotify": "f1bc",
- "square": "f0c8",
- "square-o": "f096",
- "stack-exchange": "f18d",
- "stack-overflow": "f16c",
- "star": "f005",
- "star-half": "f089",
- "star-half-empty": "f123",
- "star-half-full": "f123",
- "star-half-o": "f123",
- "star-o": "f006",
- "steam": "f1b6",
- "steam-square": "f1b7",
- "step-backward": "f048",
- "step-forward": "f051",
- "stethoscope": "f0f1",
- "sticky-note": "f249",
- "sticky-note-o": "f24a",
- "stop": "f04d",
- "stop-circle": "f28d",
- "stop-circle-o": "f28e",
- "street-view": "f21d",
- "strikethrough": "f0cc",
- "stumbleupon": "f1a4",
- "stumbleupon-circle": "f1a3",
- "subscript": "f12c",
- "subway": "f239",
- "suitcase": "f0f2",
- "sun-o": "f185",
- "superscript": "f12b",
- "support": "f1cd",
- "table": "f0ce",
- "tablet": "f10a",
- "tachometer": "f0e4",
- "tag": "f02b",
- "tags": "f02c",
- "tasks": "f0ae",
- "taxi": "f1ba",
- "television": "f26c",
- "tencent-weibo": "f1d5",
- "terminal": "f120",
- "text-height": "f034",
- "text-width": "f035",
- "th": "f00a",
- "th-large": "f009",
- "th-list": "f00b",
- "thumb-tack": "f08d",
- "thumbs-down": "f165",
- "thumbs-o-down": "f088",
- "thumbs-o-up": "f087",
- "thumbs-up": "f164",
- "ticket": "f145",
- "times": "f00d",
- "times-circle": "f057",
- "times-circle-o": "f05c",
- "tint": "f043",
- "toggle-down": "f150",
- "toggle-left": "f191",
- "toggle-off": "f204",
- "toggle-on": "f205",
- "toggle-right": "f152",
- "toggle-up": "f151",
- "trademark": "f25c",
- "train": "f238",
- "transgender": "f224",
- "transgender-alt": "f225",
- "trash": "f1f8",
- "trash-o": "f014",
- "tree": "f1bb",
- "trello": "f181",
- "tripadvisor": "f262",
- "trophy": "f091",
- "truck": "f0d1",
- "try": "f195",
- "tty": "f1e4",
- "tumblr": "f173",
- "tumblr-square": "f174",
- "turkish-lira": "f195",
- "tv": "f26c",
- "twitch": "f1e8",
- "twitter": "f099",
- "twitter-square": "f081",
- "umbrella": "f0e9",
- "underline": "f0cd",
- "undo": "f0e2",
- "university": "f19c",
- "unlink": "f127",
- "unlock": "f09c",
- "unlock-alt": "f13e",
- "unsorted": "f0dc",
- "upload": "f093",
- "usb": "f287",
- "usd": "f155",
- "user": "f007",
- "user-md": "f0f0",
- "user-plus": "f234",
- "user-secret": "f21b",
- "user-times": "f235",
- "users": "f0c0",
- "venus": "f221",
- "venus-double": "f226",
- "venus-mars": "f228",
- "viacoin": "f237",
- "video-camera": "f03d",
- "vimeo": "f27d",
- "vimeo-square": "f194",
- "vine": "f1ca",
- "vk": "f189",
- "volume-down": "f027",
- "volume-off": "f026",
- "volume-up": "f028",
- "warning": "f071",
- "wechat": "f1d7",
- "weibo": "f18a",
- "weixin": "f1d7",
- "whatsapp": "f232",
- "wheelchair": "f193",
- "wifi": "f1eb",
- "wikipedia-w": "f266",
- "windows": "f17a",
- "won": "f159",
- "wordpress": "f19a",
- "wrench": "f0ad",
- "xing": "f168",
- "xing-square": "f169",
- "y-combinator": "f23b",
- "y-combinator-square": "f1d4",
- "yahoo": "f19e",
- "yc": "f23b",
- "yc-square": "f1d4",
- "yelp": "f1e9",
- "yen": "f157",
- "youtube": "f167",
- "youtube-play": "f16a",
- "youtube-square": "f166"
-}
\ No newline at end of file
diff --git a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/fontawesome-webfont.ttf b/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/fontawesome-webfont.ttf
deleted file mode 100644
index 26dea7951a..0000000000
Binary files a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/fonts/fontawesome-webfont.ttf and /dev/null differ
diff --git a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/iconic_font.py b/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/iconic_font.py
deleted file mode 100644
index ce95f9e74f..0000000000
--- a/client/ayon_core/tools/pyblish_pype/vendor/qtawesome/iconic_font.py
+++ /dev/null
@@ -1,286 +0,0 @@
-"""Classes handling iconic fonts"""
-
-from __future__ import print_function
-
-import json
-import os
-
-from qtpy import QtCore, QtGui
-
-
-_default_options = {
- 'color': QtGui.QColor(50, 50, 50),
- 'color_disabled': QtGui.QColor(150, 150, 150),
- 'opacity': 1.0,
- 'scale_factor': 1.0,
-}
-
-
-def set_global_defaults(**kwargs):
- """Set global defaults for all icons"""
- valid_options = ['active', 'animation', 'color', 'color_active',
- 'color_disabled', 'color_selected', 'disabled', 'offset',
- 'scale_factor', 'selected']
- for kw in kwargs:
- if kw in valid_options:
- _default_options[kw] = kwargs[kw]
- else:
- error = "Invalid option '{0}'".format(kw)
- raise KeyError(error)
-
-
-class CharIconPainter:
-
- """Char icon painter"""
-
- def paint(self, iconic, painter, rect, mode, state, options):
- """Main paint method"""
- for opt in options:
- self._paint_icon(iconic, painter, rect, mode, state, opt)
-
- def _paint_icon(self, iconic, painter, rect, mode, state, options):
- """Paint a single icon"""
- painter.save()
- color, char = options['color'], options['char']
-
- if mode == QtGui.QIcon.Disabled:
- color = options.get('color_disabled', color)
- char = options.get('disabled', char)
- elif mode == QtGui.QIcon.Active:
- color = options.get('color_active', color)
- char = options.get('active', char)
- elif mode == QtGui.QIcon.Selected:
- color = options.get('color_selected', color)
- char = options.get('selected', char)
-
- painter.setPen(QtGui.QColor(color))
- # A 16 pixel-high icon yields a font size of 14, which is pixel perfect
- # for font-awesome. 16 * 0.875 = 14
- # The reason for not using full-sized glyphs is the negative bearing of
- # fonts.
- draw_size = 0.875 * round(rect.height() * options['scale_factor'])
- prefix = options['prefix']
-
- # Animation setup hook
- animation = options.get('animation')
- if animation is not None:
- animation.setup(self, painter, rect)
-
- painter.setFont(iconic.font(prefix, draw_size))
- if 'offset' in options:
- rect = QtCore.QRect(rect)
- rect.translate(options['offset'][0] * rect.width(),
- options['offset'][1] * rect.height())
-
- painter.setOpacity(options.get('opacity', 1.0))
-
- painter.drawText(rect,
- QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter,
- char)
- painter.restore()
-
-
-class CharIconEngine(QtGui.QIconEngine):
-
- """Specialization of QtGui.QIconEngine used to draw font-based icons"""
-
- def __init__(self, iconic, painter, options):
- super(CharIconEngine, self).__init__()
- self.iconic = iconic
- self.painter = painter
- self.options = options
-
- def paint(self, painter, rect, mode, state):
- self.painter.paint(
- self.iconic, painter, rect, mode, state, self.options)
-
- def pixmap(self, size, mode, state):
- pm = QtGui.QPixmap(size)
- pm.fill(QtCore.Qt.transparent)
- self.paint(QtGui.QPainter(pm),
- QtCore.QRect(QtCore.QPoint(0, 0), size),
- mode,
- state)
- return pm
-
-
-class IconicFont(QtCore.QObject):
-
- """Main class for managing iconic fonts"""
-
- def __init__(self, *args):
- """Constructor
-
- :param *args: tuples
- Each positional argument is a tuple of 3 or 4 values
- - The prefix string to be used when accessing a given font set
- - The ttf font filename
- - The json charmap filename
- - Optionally, the directory containing these files. When not
- provided, the files will be looked up in ./fonts/
- """
- super(IconicFont, self).__init__()
- self.painter = CharIconPainter()
- self.painters = {}
- self.fontname = {}
- self.charmap = {}
- for fargs in args:
- self.load_font(*fargs)
-
- def load_font(self,
- prefix,
- ttf_filename,
- charmap_filename,
- directory=None):
- """Loads a font file and the associated charmap
-
- If `directory` is None, the files will be looked up in ./fonts/
-
- Arguments
- ---------
- prefix: str
- prefix string to be used when accessing a given font set
- ttf_filename: str
- ttf font filename
- charmap_filename: str
- charmap filename
- directory: str or None, optional
- directory for font and charmap files
- """
-
- def hook(obj):
- result = {}
- for key in obj:
- result[key] = chr(int(obj[key], 16))
- return result
-
- if directory is None:
- directory = os.path.join(
- os.path.dirname(os.path.realpath(__file__)), 'fonts')
-
- with open(os.path.join(directory, charmap_filename), 'r') as codes:
- self.charmap[prefix] = json.load(codes, object_hook=hook)
-
- id_ = QtGui.QFontDatabase.addApplicationFont(
- os.path.join(directory, ttf_filename))
-
- loadedFontFamilies = QtGui.QFontDatabase.applicationFontFamilies(id_)
-
- if(loadedFontFamilies):
- self.fontname[prefix] = loadedFontFamilies[0]
- else:
- print('Font is empty')
-
- def icon(self, *names, **kwargs):
- """Returns a QtGui.QIcon object corresponding to the provided icon name
- (including prefix)
-
- Arguments
- ---------
- names: list of str
- icon name, of the form PREFIX.NAME
-
- options: dict
- options to be passed to the icon painter
- """
- options_list = kwargs.pop('options', [{}] * len(names))
- general_options = kwargs
-
- if len(options_list) != len(names):
- error = '"options" must be a list of size {0}'.format(len(names))
- raise Exception(error)
-
- parsed_options = []
- for i in range(len(options_list)):
- specific_options = options_list[i]
- parsed_options.append(self._parse_options(specific_options,
- general_options,
- names[i]))
-
- # Process high level API
- api_options = parsed_options
-
- return self._icon_by_painter(self.painter, api_options)
-
- def _parse_options(self, specific_options, general_options, name):
- """ """
- options = dict(_default_options, **general_options)
- options.update(specific_options)
-
- # Handle icons for states
- icon_kw = ['disabled', 'active', 'selected', 'char']
- names = [options.get(kw, name) for kw in icon_kw]
- prefix, chars = self._get_prefix_chars(names)
- options.update(dict(zip(*(icon_kw, chars))))
- options.update({'prefix': prefix})
-
- # Handle colors for states
- color_kw = ['color_active', 'color_selected']
- colors = [options.get(kw, options['color']) for kw in color_kw]
- options.update(dict(zip(*(color_kw, colors))))
-
- return options
-
- def _get_prefix_chars(self, names):
- """ """
- chars = []
- for name in names:
- if '.' in name:
- prefix, n = name.split('.')
- if prefix in self.charmap:
- if n in self.charmap[prefix]:
- chars.append(self.charmap[prefix][n])
- else:
- error = 'Invalid icon name "{0}" in font "{1}"'.format(
- n, prefix)
- raise Exception(error)
- else:
- error = 'Invalid font prefix "{0}"'.format(prefix)
- raise Exception(error)
- else:
- raise Exception('Invalid icon name')
-
- return prefix, chars
-
- def font(self, prefix, size):
- """Returns QtGui.QFont corresponding to the given prefix and size
-
- Arguments
- ---------
- prefix: str
- prefix string of the loaded font
- size: int
- size for the font
- """
- font = QtGui.QFont(self.fontname[prefix])
- font.setPixelSize(size)
- return font
-
- def set_custom_icon(self, name, painter):
- """Associates a user-provided CharIconPainter to an icon name
- The custom icon can later be addressed by calling
- icon('custom.NAME') where NAME is the provided name for that icon.
-
- Arguments
- ---------
- name: str
- name of the custom icon
- painter: CharIconPainter
- The icon painter, implementing
- `paint(self, iconic, painter, rect, mode, state, options)`
- """
- self.painters[name] = painter
-
- def _custom_icon(self, name, **kwargs):
- """Returns the custom icon corresponding to the given name"""
- options = dict(_default_options, **kwargs)
- if name in self.painters:
- painter = self.painters[name]
- return self._icon_by_painter(painter, options)
- else:
- return QtGui.QIcon()
-
- def _icon_by_painter(self, painter, options):
- """Returns the icon corresponding to the given painter"""
- engine = CharIconEngine(self, painter, options)
- return QtGui.QIcon(engine)
diff --git a/client/ayon_core/tools/pyblish_pype/version.py b/client/ayon_core/tools/pyblish_pype/version.py
deleted file mode 100644
index 5f1dce8011..0000000000
--- a/client/ayon_core/tools/pyblish_pype/version.py
+++ /dev/null
@@ -1,11 +0,0 @@
-
-VERSION_MAJOR = 2
-VERSION_MINOR = 9
-VERSION_PATCH = 0
-
-
-version_info = (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)
-version = '%i.%i.%i' % version_info
-__version__ = version
-
-__all__ = ['version', 'version_info', '__version__']
diff --git a/client/ayon_core/tools/pyblish_pype/view.py b/client/ayon_core/tools/pyblish_pype/view.py
deleted file mode 100644
index cc6604fc63..0000000000
--- a/client/ayon_core/tools/pyblish_pype/view.py
+++ /dev/null
@@ -1,334 +0,0 @@
-from qtpy import QtCore, QtWidgets
-from . import model
-from .constants import Roles, EXPANDER_WIDTH
-# Imported when used
-widgets = None
-
-
-def _import_widgets():
- global widgets
- if widgets is None:
- from . import widgets
-
-
-class OverviewView(QtWidgets.QTreeView):
- # An item is requesting to be toggled, with optional forced-state
- toggled = QtCore.Signal(QtCore.QModelIndex, object)
- show_perspective = QtCore.Signal(QtCore.QModelIndex)
-
- def __init__(self, parent=None):
- super(OverviewView, self).__init__(parent)
-
- self.horizontalScrollBar().hide()
- self.viewport().setAttribute(QtCore.Qt.WA_Hover, True)
- self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
- self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
- self.setItemsExpandable(True)
- self.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
- self.setHeaderHidden(True)
- self.setRootIsDecorated(False)
- self.setIndentation(0)
-
- def event(self, event):
- if not event.type() == QtCore.QEvent.KeyPress:
- return super(OverviewView, self).event(event)
-
- elif event.key() == QtCore.Qt.Key_Space:
- for index in self.selectionModel().selectedIndexes():
- self.toggled.emit(index, None)
-
- return True
-
- elif event.key() == QtCore.Qt.Key_Backspace:
- for index in self.selectionModel().selectedIndexes():
- self.toggled.emit(index, False)
-
- return True
-
- elif event.key() == QtCore.Qt.Key_Return:
- for index in self.selectionModel().selectedIndexes():
- self.toggled.emit(index, True)
-
- return True
-
- return super(OverviewView, self).event(event)
-
- def focusOutEvent(self, event):
- self.selectionModel().clear()
-
- def mouseReleaseEvent(self, event):
- if event.button() in (QtCore.Qt.LeftButton, QtCore.Qt.RightButton):
- # Deselect all group labels
- indexes = self.selectionModel().selectedIndexes()
- for index in indexes:
- if index.data(Roles.TypeRole) == model.GroupType:
- self.selectionModel().select(
- index, QtCore.QItemSelectionModel.Deselect
- )
-
- return super(OverviewView, self).mouseReleaseEvent(event)
-
-
-class PluginView(OverviewView):
- def __init__(self, *args, **kwargs):
- super(PluginView, self).__init__(*args, **kwargs)
- self.clicked.connect(self.item_expand)
-
- def item_expand(self, index):
- if index.data(Roles.TypeRole) == model.GroupType:
- if self.isExpanded(index):
- self.collapse(index)
- else:
- self.expand(index)
-
- def mouseReleaseEvent(self, event):
- if event.button() == QtCore.Qt.LeftButton:
- indexes = self.selectionModel().selectedIndexes()
- if len(indexes) == 1:
- index = indexes[0]
- pos_index = self.indexAt(event.pos())
- # If instance or Plugin and is selected
- if (
- index == pos_index
- and index.data(Roles.TypeRole) == model.PluginType
- ):
- if event.pos().x() < 20:
- self.toggled.emit(index, None)
- elif event.pos().x() > self.width() - 20:
- self.show_perspective.emit(index)
-
- return super(PluginView, self).mouseReleaseEvent(event)
-
-
-class InstanceView(OverviewView):
- def __init__(self, *args, **kwargs):
- super(InstanceView, self).__init__(*args, **kwargs)
- self.setSortingEnabled(True)
- self.sortByColumn(0, QtCore.Qt.AscendingOrder)
- self.viewport().setMouseTracking(True)
- self._pressed_group_index = None
- self._pressed_expander = None
-
- def mouseMoveEvent(self, event):
- index = self.indexAt(event.pos())
- if index.data(Roles.TypeRole) == model.GroupType:
- self.update(index)
- super(InstanceView, self).mouseMoveEvent(event)
-
- def item_expand(self, index, expand=None):
- if expand is None:
- expand = not self.isExpanded(index)
-
- if expand:
- self.expand(index)
- else:
- self.collapse(index)
-
- def group_toggle(self, index):
- if not index.isValid():
- return
- model = index.model()
-
- chilren_indexes_checked = []
- chilren_indexes_unchecked = []
- for idx in range(model.rowCount(index)):
- child_index = model.index(idx, 0, index)
- if not child_index.data(Roles.IsEnabledRole):
- continue
-
- if child_index.data(QtCore.Qt.CheckStateRole):
- chilren_indexes_checked.append(child_index)
- else:
- chilren_indexes_unchecked.append(child_index)
-
- if chilren_indexes_checked:
- to_change_indexes = chilren_indexes_checked
- new_state = False
- else:
- to_change_indexes = chilren_indexes_unchecked
- new_state = True
-
- for index in to_change_indexes:
- model.setData(index, new_state, QtCore.Qt.CheckStateRole)
- self.toggled.emit(index, new_state)
-
- def _mouse_press(self, event):
- if event.button() != QtCore.Qt.LeftButton:
- return
-
- self._pressed_group_index = None
- self._pressed_expander = None
-
- pos_index = self.indexAt(event.pos())
- if not pos_index.isValid():
- return
-
- if pos_index.data(Roles.TypeRole) != model.InstanceType:
- self._pressed_group_index = pos_index
- if event.pos().x() < 20:
- self._pressed_expander = True
- else:
- self._pressed_expander = False
-
- elif event.pos().x() < 20:
- indexes = self.selectionModel().selectedIndexes()
- any_checked = False
- if len(indexes) <= 1:
- return
-
- if pos_index in indexes:
- for index in indexes:
- if index.data(QtCore.Qt.CheckStateRole):
- any_checked = True
- break
-
- for index in indexes:
- self.toggled.emit(index, not any_checked)
- return True
- self.toggled.emit(pos_index, not any_checked)
-
- def mousePressEvent(self, event):
- if self._mouse_press(event):
- return
- return super(InstanceView, self).mousePressEvent(event)
-
- def _mouse_release(self, event, pressed_expander, pressed_index):
- if event.button() != QtCore.Qt.LeftButton:
- return
-
- pos_index = self.indexAt(event.pos())
- if not pos_index.isValid():
- return
-
- if pos_index.data(Roles.TypeRole) == model.InstanceType:
- indexes = self.selectionModel().selectedIndexes()
- if len(indexes) == 1 and indexes[0] == pos_index:
- if event.pos().x() < 20:
- self.toggled.emit(indexes[0], None)
- elif event.pos().x() > self.width() - 20:
- self.show_perspective.emit(indexes[0])
- return True
- return
-
- if pressed_index != pos_index:
- return
-
- if self.state() == QtWidgets.QTreeView.State.DragSelectingState:
- indexes = self.selectionModel().selectedIndexes()
- if len(indexes) != 1 or indexes[0] != pos_index:
- return
-
- if event.pos().x() < EXPANDER_WIDTH:
- if pressed_expander is True:
- self.item_expand(pos_index)
- return True
- else:
- if pressed_expander is False:
- self.group_toggle(pos_index)
- self.item_expand(pos_index, True)
- return True
-
- def mouseReleaseEvent(self, event):
- pressed_index = self._pressed_group_index
- pressed_expander = self._pressed_expander is True
- self._pressed_group_index = None
- self._pressed_expander = None
- result = self._mouse_release(event, pressed_expander, pressed_index)
- if result:
- return
- return super(InstanceView, self).mouseReleaseEvent(event)
-
-
-class TerminalView(QtWidgets.QTreeView):
- # An item is requesting to be toggled, with optional forced-state
- def __init__(self, parent=None):
- super(TerminalView, self).__init__(parent)
- self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
- self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
- self.setAutoScroll(False)
- self.setHeaderHidden(True)
- self.setIndentation(0)
- self.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
- self.verticalScrollBar().setSingleStep(10)
- self.setRootIsDecorated(False)
-
- self.clicked.connect(self.item_expand)
-
- _import_widgets()
-
- def event(self, event):
- if not event.type() == QtCore.QEvent.KeyPress:
- return super(TerminalView, self).event(event)
-
- elif event.key() == QtCore.Qt.Key_Space:
- for index in self.selectionModel().selectedIndexes():
- if self.isExpanded(index):
- self.collapse(index)
- else:
- self.expand(index)
-
- elif event.key() == QtCore.Qt.Key_Backspace:
- for index in self.selectionModel().selectedIndexes():
- self.collapse(index)
-
- elif event.key() == QtCore.Qt.Key_Return:
- for index in self.selectionModel().selectedIndexes():
- self.expand(index)
-
- return super(TerminalView, self).event(event)
-
- def focusOutEvent(self, event):
- self.selectionModel().clear()
-
- def item_expand(self, index):
- if index.data(Roles.TypeRole) == model.TerminalLabelType:
- if self.isExpanded(index):
- self.collapse(index)
- else:
- self.expand(index)
- self.model().layoutChanged.emit()
- self.updateGeometry()
-
- def rowsInserted(self, parent, start, end):
- """Automatically scroll to bottom on each new item added."""
- super(TerminalView, self).rowsInserted(parent, start, end)
- self.updateGeometry()
- self.scrollToBottom()
-
- def expand(self, index):
- """Wrapper to set widget for expanded index."""
- model = index.model()
- row_count = model.rowCount(index)
- is_new = False
- for child_idx in range(row_count):
- child_index = model.index(child_idx, index.column(), index)
- widget = self.indexWidget(child_index)
- if widget is None:
- is_new = True
- msg = child_index.data(QtCore.Qt.DisplayRole)
- widget = widgets.TerminalDetail(msg)
- self.setIndexWidget(child_index, widget)
- super(TerminalView, self).expand(index)
- if is_new:
- self.updateGeometries()
-
- def resizeEvent(self, event):
- super(self.__class__, self).resizeEvent(event)
- self.model().layoutChanged.emit()
-
- def sizeHint(self):
- size = super(TerminalView, self).sizeHint()
- height = (
- self.contentsMargins().top()
- + self.contentsMargins().bottom()
- )
- for idx_i in range(self.model().rowCount()):
- index = self.model().index(idx_i, 0)
- height += self.rowHeight(index)
- if self.isExpanded(index):
- for idx_j in range(index.model().rowCount(index)):
- child_index = index.child(idx_j, 0)
- height += self.rowHeight(child_index)
-
- size.setHeight(height)
- return size
diff --git a/client/ayon_core/tools/pyblish_pype/widgets.py b/client/ayon_core/tools/pyblish_pype/widgets.py
deleted file mode 100644
index 6adcc55f06..0000000000
--- a/client/ayon_core/tools/pyblish_pype/widgets.py
+++ /dev/null
@@ -1,555 +0,0 @@
-import sys
-from qtpy import QtCore, QtWidgets, QtGui
-from . import model, delegate, view, awesome
-from .constants import PluginStates, InstanceStates, Roles
-
-
-class EllidableLabel(QtWidgets.QLabel):
- def __init__(self, *args, **kwargs):
- super(EllidableLabel, self).__init__(*args, **kwargs)
- self.setObjectName("EllidableLabel")
-
- def paintEvent(self, event):
- painter = QtGui.QPainter(self)
-
- metrics = QtGui.QFontMetrics(self.font())
- elided = metrics.elidedText(
- self.text(), QtCore.Qt.ElideRight, self.width()
- )
- painter.drawText(self.rect(), self.alignment(), elided)
-
-
-class PerspectiveLabel(QtWidgets.QTextEdit):
- def __init__(self, parent=None):
- super(PerspectiveLabel, self).__init__(parent)
- self.setObjectName("PerspectiveLabel")
-
- size_policy = self.sizePolicy()
- size_policy.setHeightForWidth(True)
- size_policy.setVerticalPolicy(QtWidgets.QSizePolicy.Preferred)
- self.setSizePolicy(size_policy)
-
- self.textChanged.connect(self.on_text_changed)
-
- def on_text_changed(self, *args, **kwargs):
- self.updateGeometry()
-
- def hasHeightForWidth(self):
- return True
-
- def heightForWidth(self, width):
- margins = self.contentsMargins()
-
- document_width = 0
- if width >= margins.left() + margins.right():
- document_width = width - margins.left() - margins.right()
-
- document = self.document().clone()
- document.setTextWidth(document_width)
-
- return margins.top() + document.size().height() + margins.bottom()
-
- def sizeHint(self):
- width = super(PerspectiveLabel, self).sizeHint().width()
- return QtCore.QSize(width, self.heightForWidth(width))
-
-
-class PerspectiveWidget(QtWidgets.QWidget):
- l_doc = "Documentation"
- l_rec = "Records"
- l_path = "Path"
-
- def __init__(self, parent):
- super(PerspectiveWidget, self).__init__(parent)
-
- self.parent_widget = parent
- main_layout = QtWidgets.QVBoxLayout(self)
-
- header_widget = QtWidgets.QWidget()
- toggle_button = QtWidgets.QPushButton(parent=header_widget)
- toggle_button.setObjectName("PerspectiveToggleBtn")
- toggle_button.setText(delegate.icons["angle-left"])
- toggle_button.setMinimumHeight(50)
- toggle_button.setFixedWidth(40)
-
- indicator = QtWidgets.QLabel("", parent=header_widget)
- indicator.setFixedWidth(30)
- indicator.setAlignment(QtCore.Qt.AlignCenter)
- indicator.setObjectName("PerspectiveIndicator")
-
- name = EllidableLabel('*Name of inspected', parent=header_widget)
-
- header_layout = QtWidgets.QHBoxLayout(header_widget)
- header_layout.setAlignment(QtCore.Qt.AlignLeft)
- header_layout.addWidget(toggle_button)
- header_layout.addWidget(indicator)
- header_layout.addWidget(name)
- header_layout.setContentsMargins(0, 0, 0, 0)
- header_layout.setSpacing(10)
- header_widget.setLayout(header_layout)
-
- main_layout.setAlignment(QtCore.Qt.AlignTop)
- main_layout.addWidget(header_widget)
-
- scroll_widget = QtWidgets.QScrollArea(self)
- scroll_widget.setObjectName("PerspectiveScrollContent")
-
- contents_widget = QtWidgets.QWidget(scroll_widget)
- contents_widget.setObjectName("PerspectiveWidgetContent")
-
- layout = QtWidgets.QVBoxLayout()
- layout.setAlignment(QtCore.Qt.AlignTop)
- layout.setContentsMargins(0, 0, 0, 0)
-
- documentation = ExpandableWidget(self, self.l_doc)
- doc_label = PerspectiveLabel()
- documentation.set_content(doc_label)
- layout.addWidget(documentation)
-
- path = ExpandableWidget(self, self.l_path)
- path_label = PerspectiveLabel()
- path.set_content(path_label)
- layout.addWidget(path)
-
- records = ExpandableWidget(self, self.l_rec)
- layout.addWidget(records)
-
- contents_widget.setLayout(layout)
-
- terminal_view = view.TerminalView()
- terminal_view.setObjectName("TerminalView")
- terminal_model = model.TerminalModel()
- terminal_proxy = model.TerminalProxy(terminal_view)
- terminal_proxy.setSourceModel(terminal_model)
-
- terminal_view.setModel(terminal_proxy)
- terminal_delegate = delegate.TerminalItem()
- terminal_view.setItemDelegate(terminal_delegate)
- records.set_content(terminal_view)
-
- scroll_widget.setWidgetResizable(True)
- scroll_widget.setWidget(contents_widget)
-
- main_layout.setContentsMargins(0, 0, 0, 0)
- main_layout.setSpacing(0)
- main_layout.addWidget(scroll_widget)
- self.setLayout(main_layout)
-
- self.terminal_view = terminal_view
- self.terminal_model = terminal_model
- self.terminal_proxy = terminal_proxy
-
- self.indicator = indicator
- self.scroll_widget = scroll_widget
- self.contents_widget = contents_widget
- self.toggle_button = toggle_button
- self.name_widget = name
- self.documentation = documentation
- self.path = path
- self.records = records
-
- self.toggle_button.clicked.connect(self.toggle_me)
-
- self.last_type = None
- self.last_item_id = None
- self.last_id = None
-
- def trim(self, docstring):
- if not docstring:
- return ""
- # Convert tabs to spaces (following the normal Python rules)
- # and split into a list of lines:
- lines = docstring.expandtabs().splitlines()
- # Determine minimum indentation (first line doesn't count):
- try:
- indent = sys.maxint
- max = sys.maxint
- except Exception:
- indent = sys.maxsize
- max = sys.maxsize
-
- for line in lines[1:]:
- stripped = line.lstrip()
- if stripped:
- indent = min(indent, len(line) - len(stripped))
- # Remove indentation (first line is special):
- trimmed = [lines[0].strip()]
- if indent < max:
- for line in lines[1:]:
- trimmed.append(line[indent:].rstrip())
- # Strip off trailing and leading blank lines:
- while trimmed and not trimmed[-1]:
- trimmed.pop()
- while trimmed and not trimmed[0]:
- trimmed.pop(0)
- # Return a single string:
- return "\n".join(trimmed)
-
- def set_indicator_state(self, state):
- self.indicator.setProperty("state", state)
- self.indicator.style().polish(self.indicator)
-
- def reset(self):
- self.last_id = None
- self.set_records(list())
- self.set_indicator_state(None)
-
- def update_context(self, plugin_item, instance_item):
- if not self.last_item_id or not self.last_type:
- return
-
- if self.last_type == model.PluginType:
- if not self.last_id:
- _item_id = plugin_item.data(Roles.ObjectUIdRole)
- if _item_id != self.last_item_id:
- return
- self.last_id = plugin_item.plugin.id
-
- elif self.last_id != plugin_item.plugin.id:
- return
-
- self.set_context(plugin_item.index())
- return
-
- if self.last_type == model.InstanceType:
- if not self.last_id:
- _item_id = instance_item.data(Roles.ObjectUIdRole)
- if _item_id != self.last_item_id:
- return
- self.last_id = instance_item.instance.id
-
- elif self.last_id != instance_item.instance.id:
- return
-
- self.set_context(instance_item.index())
- return
-
- def set_context(self, index):
- if not index or not index.isValid():
- index_type = None
- else:
- index_type = index.data(Roles.TypeRole)
-
- if index_type == model.InstanceType:
- item_id = index.data(Roles.ObjectIdRole)
- publish_states = index.data(Roles.PublishFlagsRole)
- if publish_states & InstanceStates.ContextType:
- type_indicator = "C"
- else:
- type_indicator = "I"
-
- if publish_states & InstanceStates.InProgress:
- self.set_indicator_state("active")
-
- elif publish_states & InstanceStates.HasError:
- self.set_indicator_state("error")
-
- elif publish_states & InstanceStates.HasWarning:
- self.set_indicator_state("warning")
-
- elif publish_states & InstanceStates.HasFinished:
- self.set_indicator_state("ok")
- else:
- self.set_indicator_state(None)
-
- self.documentation.setVisible(False)
- self.path.setVisible(False)
-
- elif index_type == model.PluginType:
- item_id = index.data(Roles.ObjectIdRole)
- type_indicator = "P"
-
- doc = index.data(Roles.DocstringRole)
- doc_str = ""
- if doc:
- doc_str = self.trim(doc)
-
- publish_states = index.data(Roles.PublishFlagsRole)
- if publish_states & PluginStates.InProgress:
- self.set_indicator_state("active")
-
- elif publish_states & PluginStates.HasError:
- self.set_indicator_state("error")
-
- elif publish_states & PluginStates.HasWarning:
- self.set_indicator_state("warning")
-
- elif publish_states & PluginStates.WasProcessed:
- self.set_indicator_state("ok")
-
- else:
- self.set_indicator_state(None)
-
- self.documentation.toggle_content(bool(doc_str))
- self.documentation.content.setText(doc_str)
-
- path = index.data(Roles.PathModuleRole) or ""
- self.path.toggle_content(path.strip() != "")
- self.path.content.setText(path)
-
- self.documentation.setVisible(True)
- self.path.setVisible(True)
-
- else:
- self.last_type = None
- self.last_id = None
- self.indicator.setText("?")
- self.set_indicator_state(None)
- self.documentation.setVisible(False)
- self.path.setVisible(False)
- self.records.setVisible(False)
- return
-
- self.last_type = index_type
- self.last_id = item_id
- self.last_item_id = index.data(Roles.ObjectUIdRole)
-
- self.indicator.setText(type_indicator)
-
- label = index.data(QtCore.Qt.DisplayRole)
- self.name_widget.setText(label)
- self.records.setVisible(True)
-
- records = index.data(Roles.LogRecordsRole) or []
- self.set_records(records)
-
- def set_records(self, records):
- len_records = 0
- if records:
- len_records += len(records)
-
- data = {"records": records}
- self.terminal_model.reset()
- self.terminal_model.update_with_result(data)
-
- self.records.button_toggle_text.setText(
- "{} ({})".format(self.l_rec, len_records)
- )
- self.records.toggle_content(len_records > 0)
-
- def toggle_me(self):
- self.parent_widget.parent().toggle_perspective_widget()
-
-
-class ClickableWidget(QtWidgets.QLabel):
- clicked = QtCore.Signal()
-
- def mouseReleaseEvent(self, event):
- if event.button() == QtCore.Qt.LeftButton:
- self.clicked.emit()
- super(ClickableWidget, self).mouseReleaseEvent(event)
-
-
-class ExpandableWidget(QtWidgets.QWidget):
-
- content = None
-
- def __init__(self, parent, title):
- super(ExpandableWidget, self).__init__(parent)
-
- top_part = ClickableWidget(parent=self)
- top_part.setObjectName("ExpandableHeader")
-
- button_size = QtCore.QSize(5, 5)
- button_toggle = QtWidgets.QToolButton(parent=top_part)
- button_toggle.setIconSize(button_size)
- button_toggle.setArrowType(QtCore.Qt.RightArrow)
- button_toggle.setCheckable(True)
- button_toggle.setChecked(False)
-
- button_toggle_text = QtWidgets.QLabel(title, parent=top_part)
-
- layout = QtWidgets.QHBoxLayout(top_part)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(5)
- layout.addWidget(button_toggle)
- layout.addWidget(button_toggle_text)
- top_part.setLayout(layout)
-
- main_layout = QtWidgets.QVBoxLayout(self)
- main_layout.setContentsMargins(9, 9, 9, 0)
-
- content = QtWidgets.QFrame(self)
- content.setObjectName("ExpandableWidgetContent")
- content.setVisible(False)
-
- content_layout = QtWidgets.QVBoxLayout(content)
-
- main_layout.addWidget(top_part)
- main_layout.addWidget(content)
- self.setLayout(main_layout)
-
- self.setAttribute(QtCore.Qt.WA_StyledBackground)
-
- self.top_part = top_part
- self.button_toggle = button_toggle
- self.button_toggle_text = button_toggle_text
-
- self.content_widget = content
- self.content_layout = content_layout
-
- self.top_part.clicked.connect(self.top_part_clicked)
- self.button_toggle.clicked.connect(self.toggle_content)
-
- def top_part_clicked(self):
- self.toggle_content(not self.button_toggle.isChecked())
-
- def toggle_content(self, *args):
- if len(args) > 0:
- checked = args[0]
- else:
- checked = self.button_toggle.isChecked()
- arrow_type = QtCore.Qt.RightArrow
- if checked:
- arrow_type = QtCore.Qt.DownArrow
- self.button_toggle.setChecked(checked)
- self.button_toggle.setArrowType(arrow_type)
- self.content_widget.setVisible(checked)
-
- def resizeEvent(self, event):
- super(ExpandableWidget, self).resizeEvent(event)
- self.content.updateGeometry()
-
- def set_content(self, in_widget):
- if self.content:
- self.content.hide()
- self.content_layout.removeWidget(self.content)
- self.content_layout.addWidget(in_widget)
- self.content = in_widget
-
-
-class ButtonWithMenu(QtWidgets.QWidget):
- def __init__(self, button_title, parent=None):
- super(ButtonWithMenu, self).__init__(parent=parent)
- self.setSizePolicy(QtWidgets.QSizePolicy(
- QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum
- ))
-
- self.layout = QtWidgets.QHBoxLayout(self)
- self.layout.setContentsMargins(0, 0, 0, 0)
- self.layout.setSpacing(0)
-
- self.menu = QtWidgets.QMenu()
- # TODO move to stylesheets
- self.menu.setStyleSheet("""
- *{color: #fff; background-color: #555; border: 1px solid #222;}
- ::item {background-color: transparent;padding: 5px;
- padding-left: 10px;padding-right: 10px;}
- ::item:selected {background-color: #666;}
- """)
-
- self.button = QtWidgets.QPushButton(button_title)
- self.button.setObjectName("ButtonWithMenu")
-
- self.layout.addWidget(self.button)
-
- self.button.clicked.connect(self.btn_clicked)
-
- def btn_clicked(self):
- self.menu.popup(self.button.mapToGlobal(
- QtCore.QPoint(0, self.button.height())
- ))
-
- def addItem(self, text, callback):
- self.menu.addAction(text, callback)
- self.button.setToolTip("Select to apply predefined presets")
-
- def clearMenu(self):
- self.menu.clear()
- self.button.setToolTip("Presets not found")
-
-
-class CommentBox(QtWidgets.QLineEdit):
-
- def __init__(self, placeholder_text, parent=None):
- super(CommentBox, self).__init__(parent=parent)
- self.placeholder = QtWidgets.QLabel(placeholder_text, self)
- self.placeholder.move(2, 2)
-
- def focusInEvent(self, event):
- self.placeholder.setVisible(False)
- return super(CommentBox, self).focusInEvent(event)
-
- def focusOutEvent(self, event):
- current_text = self.text()
- current_text = current_text.strip(" ")
- self.setText(current_text)
- if not self.text():
- self.placeholder.setVisible(True)
- return super(CommentBox, self).focusOutEvent(event)
-
-
-class TerminalDetail(QtWidgets.QTextEdit):
- def __init__(self, text, *args, **kwargs):
- super(TerminalDetail, self).__init__(*args, **kwargs)
-
- self.setReadOnly(True)
- self.setHtml(text)
- self.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
- self.setWordWrapMode(
- QtGui.QTextOption.WrapAtWordBoundaryOrAnywhere
- )
-
- def sizeHint(self):
- content_margins = (
- self.contentsMargins().top()
- + self.contentsMargins().bottom()
- )
- size = self.document().documentLayout().documentSize().toSize()
- size.setHeight(size.height() + content_margins)
- return size
-
-
-class FilterButton(QtWidgets.QPushButton):
- def __init__(self, name, *args, **kwargs):
- self.filter_name = name
-
- super(FilterButton, self).__init__(*args, **kwargs)
-
- self.toggled.connect(self.on_toggle)
-
- self.setProperty("type", name)
- self.setObjectName("TerminalFilerBtn")
- self.setCheckable(True)
- self.setChecked(
- model.TerminalProxy.filter_buttons_checks[name]
- )
-
- def on_toggle(self, toggle_state):
- model.TerminalProxy.change_filter(self.filter_name, toggle_state)
-
-
-class TerminalFilterWidget(QtWidgets.QWidget):
- # timer.timeout.connect(lambda: self._update(self.parent_widget))
- def __init__(self, *args, **kwargs):
- super(TerminalFilterWidget, self).__init__(*args, **kwargs)
- self.setObjectName("TerminalFilterWidget")
- self.filter_changed = QtCore.Signal()
-
- info_icon = awesome.tags["info"]
- log_icon = awesome.tags["circle"]
- error_icon = awesome.tags["exclamation-triangle"]
-
- filter_buttons = (
- FilterButton("info", info_icon, self),
- FilterButton("log_debug", log_icon, self),
- FilterButton("log_info", log_icon, self),
- FilterButton("log_warning", log_icon, self),
- FilterButton("log_error", log_icon, self),
- FilterButton("log_critical", log_icon, self),
- FilterButton("error", error_icon, self)
- )
-
- layout = QtWidgets.QHBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- # Add spacers
- spacer = QtWidgets.QWidget()
- spacer.setAttribute(QtCore.Qt.WA_TranslucentBackground)
- layout.addWidget(spacer, 1)
-
- for btn in filter_buttons:
- layout.addWidget(btn)
-
- self.setLayout(layout)
-
- self.filter_buttons = filter_buttons
diff --git a/client/ayon_core/tools/pyblish_pype/window.py b/client/ayon_core/tools/pyblish_pype/window.py
deleted file mode 100644
index 01d373d841..0000000000
--- a/client/ayon_core/tools/pyblish_pype/window.py
+++ /dev/null
@@ -1,1315 +0,0 @@
-"""Main Window
-
-States:
- These are all possible states and their transitions.
-
-
- reset
- '
- '
- '
- ___v__
- | | reset
- | Idle |--------------------.
- | |<-------------------'
- | |
- | | _____________
- | | validate | | reset # TODO
- | |----------------->| In-progress |-----------.
- | | |_____________| '
- | |<-------------------------------------------'
- | |
- | | _____________
- | | publish | |
- | |----------------->| In-progress |---.
- | | |_____________| '
- | |<-----------------------------------'
- |______|
-
-
-Todo:
- There are notes spread throughout this project with the syntax:
-
- - TODO(username)
-
- The `username` is a quick and dirty indicator of who made the note
- and is by no means exclusive to that person in terms of seeing it
- done. Feel free to do, or make your own TODO's as you code. Just
- make sure the description is sufficient for anyone reading it for
- the first time to understand how to actually to it!
-
-"""
-import sys
-from functools import partial
-
-from . import delegate, model, settings, util, view, widgets
-from .awesome import tags as awesome
-
-from qtpy import QtCore, QtGui, QtWidgets
-from .constants import (
- PluginStates, PluginActionStates, InstanceStates, GroupStates, Roles
-)
-if sys.version_info[0] == 3:
- from queue import Queue
-else:
- from Queue import Queue
-
-
-class Window(QtWidgets.QDialog):
- def __init__(self, controller, parent=None):
- super(Window, self).__init__(parent=parent)
-
- self._suspend_logs = False
-
- # Use plastique style for specific ocations
- # TODO set style name via environment variable
- low_keys = {
- key.lower(): key
- for key in QtWidgets.QStyleFactory.keys()
- }
- if "plastique" in low_keys:
- self.setStyle(
- QtWidgets.QStyleFactory.create(low_keys["plastique"])
- )
-
- icon = QtGui.QIcon(util.get_asset("img", "logo-extrasmall.png"))
- if parent is None:
- on_top_flag = QtCore.Qt.WindowStaysOnTopHint
- else:
- on_top_flag = QtCore.Qt.Dialog
-
- self.setWindowFlags(
- self.windowFlags()
- | QtCore.Qt.WindowTitleHint
- | QtCore.Qt.WindowMaximizeButtonHint
- | QtCore.Qt.WindowMinimizeButtonHint
- | QtCore.Qt.WindowCloseButtonHint
- | on_top_flag
- )
- self.setWindowIcon(icon)
- self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
-
- self.controller = controller
-
- main_widget = QtWidgets.QWidget(self)
-
- # General layout
- header_widget = QtWidgets.QWidget(parent=main_widget)
-
- header_tab_widget = QtWidgets.QWidget(header_widget)
- header_tab_overview = QtWidgets.QRadioButton(header_tab_widget)
- header_tab_terminal = QtWidgets.QRadioButton(header_tab_widget)
- header_spacer = QtWidgets.QWidget(header_tab_widget)
-
- button_suspend_logs_widget = QtWidgets.QWidget()
- button_suspend_logs_widget_layout = QtWidgets.QHBoxLayout(
- button_suspend_logs_widget
- )
- button_suspend_logs_widget_layout.setContentsMargins(0, 10, 0, 10)
- button_suspend_logs = QtWidgets.QPushButton(header_widget)
- button_suspend_logs.setFixedWidth(7)
- button_suspend_logs.setSizePolicy(
- QtWidgets.QSizePolicy.Preferred,
- QtWidgets.QSizePolicy.Expanding
- )
- button_suspend_logs_widget_layout.addWidget(button_suspend_logs)
- header_aditional_btns = QtWidgets.QWidget(header_tab_widget)
-
- aditional_btns_layout = QtWidgets.QHBoxLayout(header_aditional_btns)
-
- presets_button = widgets.ButtonWithMenu(awesome["filter"])
- presets_button.setEnabled(False)
- aditional_btns_layout.addWidget(presets_button)
-
- layout_tab = QtWidgets.QHBoxLayout(header_tab_widget)
- layout_tab.setContentsMargins(0, 0, 0, 0)
- layout_tab.setSpacing(0)
- layout_tab.addWidget(header_tab_overview, 0)
- layout_tab.addWidget(header_tab_terminal, 0)
- layout_tab.addWidget(button_suspend_logs_widget, 0)
-
- # Compress items to the left
- layout_tab.addWidget(header_spacer, 1)
- layout_tab.addWidget(header_aditional_btns, 0)
-
- layout = QtWidgets.QHBoxLayout(header_widget)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(0)
- layout.addWidget(header_tab_widget)
-
- header_widget.setLayout(layout)
-
- # Overview Page
- # TODO add parent
- overview_page = QtWidgets.QWidget()
-
- overview_instance_view = view.InstanceView(parent=overview_page)
- overview_instance_view.setAnimated(settings.Animated)
- overview_instance_delegate = delegate.InstanceDelegate(
- parent=overview_instance_view
- )
- instance_model = model.InstanceModel(controller)
- instance_sort_proxy = model.InstanceSortProxy()
- instance_sort_proxy.setSourceModel(instance_model)
-
- overview_instance_view.setItemDelegate(overview_instance_delegate)
- overview_instance_view.setModel(instance_sort_proxy)
-
- overview_plugin_view = view.PluginView(parent=overview_page)
- overview_plugin_view.setAnimated(settings.Animated)
- overview_plugin_delegate = delegate.PluginDelegate(
- parent=overview_plugin_view
- )
- overview_plugin_view.setItemDelegate(overview_plugin_delegate)
- plugin_model = model.PluginModel(controller)
- plugin_proxy = model.PluginFilterProxy()
- plugin_proxy.setSourceModel(plugin_model)
- overview_plugin_view.setModel(plugin_proxy)
-
- layout = QtWidgets.QHBoxLayout(overview_page)
- layout.addWidget(overview_instance_view, 1)
- layout.addWidget(overview_plugin_view, 1)
- layout.setContentsMargins(5, 5, 5, 5)
- layout.setSpacing(0)
- overview_page.setLayout(layout)
-
- # Terminal
- terminal_container = QtWidgets.QWidget()
-
- terminal_view = view.TerminalView()
- terminal_model = model.TerminalModel()
- terminal_proxy = model.TerminalProxy(terminal_view)
- terminal_proxy.setSourceModel(terminal_model)
-
- terminal_view.setModel(terminal_proxy)
- terminal_delegate = delegate.TerminalItem()
- terminal_view.setItemDelegate(terminal_delegate)
-
- layout = QtWidgets.QVBoxLayout(terminal_container)
- layout.addWidget(terminal_view)
- layout.setContentsMargins(5, 5, 5, 5)
- layout.setSpacing(0)
-
- terminal_container.setLayout(layout)
-
- terminal_page = QtWidgets.QWidget()
- layout = QtWidgets.QVBoxLayout(terminal_page)
- layout.addWidget(terminal_container)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(0)
-
- # Add some room between window borders and contents
- body_widget = QtWidgets.QWidget(main_widget)
- layout = QtWidgets.QHBoxLayout(body_widget)
- layout.setContentsMargins(5, 5, 5, 1)
- layout.addWidget(overview_page)
- layout.addWidget(terminal_page)
-
- # Comment Box
- comment_box = widgets.CommentBox("Comment...", self)
-
- intent_box = QtWidgets.QComboBox()
-
- intent_model = model.IntentModel()
- intent_box.setModel(intent_model)
-
- comment_intent_widget = QtWidgets.QWidget()
- comment_intent_layout = QtWidgets.QHBoxLayout(comment_intent_widget)
- comment_intent_layout.setContentsMargins(0, 0, 0, 0)
- comment_intent_layout.setSpacing(5)
- comment_intent_layout.addWidget(comment_box)
- comment_intent_layout.addWidget(intent_box)
-
- # Terminal filtering
- terminal_filters_widget = widgets.TerminalFilterWidget()
-
- # Footer
- footer_widget = QtWidgets.QWidget(main_widget)
-
- footer_info = QtWidgets.QLabel(footer_widget)
- footer_spacer = QtWidgets.QWidget(footer_widget)
-
- footer_button_stop = QtWidgets.QPushButton(
- awesome["stop"], footer_widget
- )
- footer_button_stop.setToolTip("Stop publishing")
- footer_button_reset = QtWidgets.QPushButton(
- awesome["refresh"], footer_widget
- )
- footer_button_reset.setToolTip("Restart publishing")
- footer_button_validate = QtWidgets.QPushButton(
- awesome["flask"], footer_widget
- )
- footer_button_validate.setToolTip("Run validations")
- footer_button_play = QtWidgets.QPushButton(
- awesome["play"], footer_widget
- )
- footer_button_play.setToolTip("Publish")
- layout = QtWidgets.QHBoxLayout()
- layout.setContentsMargins(5, 5, 5, 5)
- layout.addWidget(footer_info, 0)
- layout.addWidget(footer_spacer, 1)
-
- layout.addWidget(footer_button_stop, 0)
- layout.addWidget(footer_button_reset, 0)
- layout.addWidget(footer_button_validate, 0)
- layout.addWidget(footer_button_play, 0)
-
- footer_layout = QtWidgets.QVBoxLayout(footer_widget)
- footer_layout.addWidget(terminal_filters_widget)
- footer_layout.addWidget(comment_intent_widget)
- footer_layout.addLayout(layout)
-
- footer_widget.setProperty("success", -1)
-
- # Placeholder for when GUI is closing
- # TODO(marcus): Fade to black and the the user about what's happening
- closing_placeholder = QtWidgets.QWidget(main_widget)
- closing_placeholder.setSizePolicy(
- QtWidgets.QSizePolicy.Expanding,
- QtWidgets.QSizePolicy.Expanding
- )
- closing_placeholder.hide()
-
- perspective_widget = widgets.PerspectiveWidget(main_widget)
- perspective_widget.hide()
-
- pages_widget = QtWidgets.QWidget(main_widget)
- layout = QtWidgets.QVBoxLayout(pages_widget)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(0)
- layout.addWidget(header_widget, 0)
- layout.addWidget(body_widget, 1)
-
- # Main layout
- layout = QtWidgets.QVBoxLayout(main_widget)
- layout.addWidget(pages_widget, 3)
- layout.addWidget(perspective_widget, 3)
- layout.addWidget(closing_placeholder, 1)
- layout.addWidget(footer_widget, 0)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(0)
- main_widget.setLayout(layout)
-
- self.main_layout = QtWidgets.QVBoxLayout(self)
- self.main_layout.setContentsMargins(0, 0, 0, 0)
- self.main_layout.setSpacing(0)
- self.main_layout.addWidget(main_widget)
-
- """Setup
-
- Widgets are referred to in CSS via their object-name. We
- use the same mechanism internally to refer to objects; so rather
- than storing widgets as self.my_widget, it is referred to as:
-
- >>> my_widget = self.findChild(QtWidgets.QWidget, "MyWidget")
-
- This way there is only ever a single method of referring to any widget.
- """
-
- names = {
- # Main
- "Header": header_widget,
- "Body": body_widget,
- "Footer": footer_widget,
-
- # Pages
- "Overview": overview_page,
- "Terminal": terminal_page,
-
- # Tabs
- "OverviewTab": header_tab_overview,
- "TerminalTab": header_tab_terminal,
-
- # Views
- "TerminalView": terminal_view,
-
- # Buttons
- "SuspendLogsBtn": button_suspend_logs,
- "Stop": footer_button_stop,
- "Reset": footer_button_reset,
- "Validate": footer_button_validate,
- "Play": footer_button_play,
-
- # Misc
- "HeaderSpacer": header_spacer,
- "FooterSpacer": footer_spacer,
- "FooterInfo": footer_info,
- "CommentIntentWidget": comment_intent_widget,
- "CommentBox": comment_box,
- "CommentPlaceholder": comment_box.placeholder,
- "ClosingPlaceholder": closing_placeholder,
- "IntentBox": intent_box
- }
-
- for name, _widget in names.items():
- _widget.setObjectName(name)
-
- # Enable CSS on plain QWidget objects
- for _widget in (
- pages_widget,
- header_widget,
- body_widget,
- comment_box,
- overview_page,
- terminal_page,
- footer_widget,
- button_suspend_logs,
- footer_button_stop,
- footer_button_reset,
- footer_button_validate,
- footer_button_play,
- footer_spacer,
- closing_placeholder
- ):
- _widget.setAttribute(QtCore.Qt.WA_StyledBackground)
-
- # Signals
- header_tab_overview.toggled.connect(
- lambda: self.on_tab_changed("overview")
- )
- header_tab_terminal.toggled.connect(
- lambda: self.on_tab_changed("terminal")
- )
-
- overview_instance_view.show_perspective.connect(
- self.toggle_perspective_widget
- )
- overview_plugin_view.show_perspective.connect(
- self.toggle_perspective_widget
- )
-
- controller.switch_toggleability.connect(self.change_toggleability)
-
- controller.was_reset.connect(self.on_was_reset)
- # This is called synchronously on each process
- controller.was_processed.connect(self.on_was_processed)
- controller.passed_group.connect(self.on_passed_group)
- controller.was_stopped.connect(self.on_was_stopped)
- controller.was_finished.connect(self.on_was_finished)
-
- controller.was_skipped.connect(self.on_was_skipped)
- controller.was_acted.connect(self.on_was_acted)
-
- # NOTE: Listeners to this signal are run in the main thread
- controller.about_to_process.connect(
- self.on_about_to_process,
- QtCore.Qt.DirectConnection
- )
-
- overview_instance_view.toggled.connect(self.on_instance_toggle)
- overview_plugin_view.toggled.connect(self.on_plugin_toggle)
-
- button_suspend_logs.clicked.connect(self.on_suspend_clicked)
- footer_button_stop.clicked.connect(self.on_stop_clicked)
- footer_button_reset.clicked.connect(self.on_reset_clicked)
- footer_button_validate.clicked.connect(self.on_validate_clicked)
- footer_button_play.clicked.connect(self.on_play_clicked)
-
- comment_box.textChanged.connect(self.on_comment_entered)
- comment_box.returnPressed.connect(self.on_play_clicked)
- overview_plugin_view.customContextMenuRequested.connect(
- self.on_plugin_action_menu_requested
- )
-
- instance_model.group_created.connect(self.on_instance_group_created)
-
- self.main_widget = main_widget
-
- self.pages_widget = pages_widget
- self.header_widget = header_widget
- self.body_widget = body_widget
-
- self.terminal_filters_widget = terminal_filters_widget
-
- self.footer_widget = footer_widget
- self.button_suspend_logs = button_suspend_logs
- self.footer_button_stop = footer_button_stop
- self.footer_button_reset = footer_button_reset
- self.footer_button_validate = footer_button_validate
- self.footer_button_play = footer_button_play
-
- self.footer_info = footer_info
-
- self.overview_instance_view = overview_instance_view
- self.overview_plugin_view = overview_plugin_view
- self.plugin_model = plugin_model
- self.plugin_proxy = plugin_proxy
- self.instance_model = instance_model
- self.instance_sort_proxy = instance_sort_proxy
-
- self.presets_button = presets_button
-
- self.terminal_model = terminal_model
- self.terminal_proxy = terminal_proxy
- self.terminal_view = terminal_view
-
- self.comment_main_widget = comment_intent_widget
- self.comment_box = comment_box
- self.intent_box = intent_box
- self.intent_model = intent_model
-
- self.perspective_widget = perspective_widget
-
- self.tabs = {
- "overview": header_tab_overview,
- "terminal": header_tab_terminal
- }
- self.pages = (
- ("overview", overview_page),
- ("terminal", terminal_page)
- )
-
- current_page = settings.InitialTab or "overview"
- self.comment_main_widget.setVisible(
- not current_page == "terminal"
- )
- self.terminal_filters_widget.setVisible(
- current_page == "terminal"
- )
-
- self._current_page = current_page
- self._hidden_for_plugin_process = False
-
- self.tabs[current_page].setChecked(True)
-
- self.apply_log_suspend_value(
- util.env_variable_to_bool("PYBLISH_SUSPEND_LOGS")
- )
-
- # -------------------------------------------------------------------------
- #
- # Event handlers
- #
- # -------------------------------------------------------------------------
- def set_presets(self, key):
- plugin_settings = self.controller.possible_presets.get(key)
- if not plugin_settings:
- return
-
- for plugin_item in self.plugin_model.plugin_items.values():
- if not plugin_item.plugin.optional:
- continue
-
- value = plugin_settings.get(
- plugin_item.plugin.__name__,
- # if plugin is not in presets then set default value
- self.controller.optional_default.get(
- plugin_item.plugin.__name__
- )
- )
- if value is None:
- continue
-
- plugin_item.setData(value, QtCore.Qt.CheckStateRole)
-
- def toggle_perspective_widget(self, index=None):
- show = False
- if index:
- show = True
- self.perspective_widget.set_context(index)
-
- self.pages_widget.setVisible(not show)
- self.perspective_widget.setVisible(show)
- self.footer_items_visibility()
-
- def change_toggleability(self, enable_value):
- for plugin_item in self.plugin_model.plugin_items.values():
- plugin_item.setData(enable_value, Roles.IsEnabledRole)
-
- for instance_item in (
- self.instance_model.instance_items.values()
- ):
- instance_item.setData(enable_value, Roles.IsEnabledRole)
-
- def _add_intent_to_context(self):
- context_value = None
- if (
- self.intent_model.has_items
- and "intent" not in self.controller.context.data
- ):
- idx = self.intent_model.index(self.intent_box.currentIndex(), 0)
- intent_value = self.intent_model.data(idx, Roles.IntentItemValue)
- intent_label = self.intent_model.data(idx, QtCore.Qt.DisplayRole)
- if intent_value:
- context_value = {
- "value": intent_value,
- "label": intent_label
- }
-
- # Unset intent if is set to empty value
- if context_value is None:
- self.controller.context.data.pop("intent", None)
- else:
- self.controller.context.data["intent"] = context_value
-
- def on_instance_toggle(self, index, state=None):
- """An item is requesting to be toggled"""
- if not index.data(Roles.IsOptionalRole):
- return self.info("This item is mandatory")
-
- if self.controller.collect_state != 1:
- return self.info("Cannot toggle")
-
- current_state = index.data(QtCore.Qt.CheckStateRole)
- if state is None:
- state = not current_state
-
- instance_id = index.data(Roles.ObjectIdRole)
- instance_item = self.instance_model.instance_items[instance_id]
- instance_item.setData(state, QtCore.Qt.CheckStateRole)
-
- self.controller.instance_toggled.emit(
- instance_item.instance, current_state, state
- )
-
- self.update_compatibility()
-
- def on_instance_group_created(self, index):
- _index = self.instance_sort_proxy.mapFromSource(index)
- self.overview_instance_view.expand(_index)
-
- def on_plugin_toggle(self, index, state=None):
- """An item is requesting to be toggled"""
- if not index.data(Roles.IsOptionalRole):
- return self.info("This item is mandatory")
-
- if self.controller.collect_state != 1:
- return self.info("Cannot toggle")
-
- if state is None:
- state = not index.data(QtCore.Qt.CheckStateRole)
-
- plugin_id = index.data(Roles.ObjectIdRole)
- plugin_item = self.plugin_model.plugin_items[plugin_id]
- plugin_item.setData(state, QtCore.Qt.CheckStateRole)
-
- self.update_compatibility()
-
- def on_tab_changed(self, target):
- previous_page = None
- target_page = None
- direction = None
- for name, page in self.pages:
- if name == target:
- target_page = page
- if direction is None:
- direction = -1
- elif name == self._current_page:
- previous_page = page
- if direction is None:
- direction = 1
- else:
- page.setVisible(False)
-
- self._current_page = target
- self.slide_page(previous_page, target_page, direction)
-
- def slide_page(self, previous_page, target_page, direction):
- if previous_page is None:
- for name, page in self.pages:
- for _name, _page in self.pages:
- if name != _name:
- _page.hide()
- page.show()
- page.hide()
-
- if (
- previous_page == target_page
- or previous_page is None
- ):
- if not target_page.isVisible():
- target_page.show()
- return
-
- if not settings.Animated:
- previous_page.setVisible(False)
- target_page.setVisible(True)
- return
-
- width = previous_page.frameGeometry().width()
- offset = QtCore.QPoint(direction * width, 0)
-
- previous_rect = (
- previous_page.frameGeometry().x(),
- previous_page.frameGeometry().y(),
- width,
- previous_page.frameGeometry().height()
- )
- curr_pos = previous_page.pos()
-
- previous_page.hide()
- target_page.show()
- target_page.update()
- target_rect = (
- target_page.frameGeometry().x(),
- target_page.frameGeometry().y(),
- target_page.frameGeometry().width(),
- target_page.frameGeometry().height()
- )
- previous_page.show()
-
- target_page.raise_()
- previous_page.setGeometry(*previous_rect)
- target_page.setGeometry(*target_rect)
-
- target_page.move(curr_pos + offset)
-
- duration = 250
-
- anim_old = QtCore.QPropertyAnimation(
- previous_page, b"pos", self
- )
- anim_old.setDuration(duration)
- anim_old.setStartValue(curr_pos)
- anim_old.setEndValue(curr_pos - offset)
- anim_old.setEasingCurve(QtCore.QEasingCurve.OutQuad)
-
- anim_new = QtCore.QPropertyAnimation(
- target_page, b"pos", self
- )
- anim_new.setDuration(duration)
- anim_new.setStartValue(curr_pos + offset)
- anim_new.setEndValue(curr_pos)
- anim_new.setEasingCurve(QtCore.QEasingCurve.OutQuad)
-
- anim_group = QtCore.QParallelAnimationGroup(self)
- anim_group.addAnimation(anim_old)
- anim_group.addAnimation(anim_new)
-
- def slide_finished():
- previous_page.hide()
- self.footer_items_visibility()
-
- anim_group.finished.connect(slide_finished)
- anim_group.start()
-
- def footer_items_visibility(
- self,
- comment_visible=None,
- terminal_filters_visibile=None
- ):
- target = self._current_page
- comment_visibility = (
- not self.perspective_widget.isVisible()
- and not target == "terminal"
- and self.comment_box.isEnabled()
- )
- terminal_filters_visibility = (
- target == "terminal"
- or self.perspective_widget.isVisible()
- )
-
- if comment_visible is not None and comment_visibility:
- comment_visibility = comment_visible
-
- if (
- terminal_filters_visibile is not None
- and terminal_filters_visibility
- ):
- terminal_filters_visibility = terminal_filters_visibile
-
- duration = 150
-
- hiding_widgets = []
- showing_widgets = []
- if (comment_visibility != (
- self.comment_main_widget.isVisible()
- )):
- if self.comment_main_widget.isVisible():
- hiding_widgets.append(self.comment_main_widget)
- else:
- showing_widgets.append(self.comment_main_widget)
-
- if (terminal_filters_visibility != (
- self.terminal_filters_widget.isVisible()
- )):
- if self.terminal_filters_widget.isVisible():
- hiding_widgets.append(self.terminal_filters_widget)
- else:
- showing_widgets.append(self.terminal_filters_widget)
-
- if not hiding_widgets and not showing_widgets:
- return
-
- hiding_widgets_queue = Queue()
- showing_widgets_queue = Queue()
- widgets_by_pos_y = {}
- for widget in hiding_widgets:
- key = widget.mapToGlobal(widget.rect().topLeft()).x()
- widgets_by_pos_y[key] = widget
-
- for key in sorted(widgets_by_pos_y.keys()):
- widget = widgets_by_pos_y[key]
- hiding_widgets_queue.put((widget, ))
-
- for widget in hiding_widgets:
- widget.hide()
-
- for widget in showing_widgets:
- widget.show()
-
- self.footer_widget.updateGeometry()
- widgets_by_pos_y = {}
- for widget in showing_widgets:
- key = widget.mapToGlobal(widget.rect().topLeft()).x()
- widgets_by_pos_y[key] = widget
-
- for key in reversed(sorted(widgets_by_pos_y.keys())):
- widget = widgets_by_pos_y[key]
- showing_widgets_queue.put(widget)
-
- for widget in showing_widgets:
- widget.hide()
-
- for widget in hiding_widgets:
- widget.show()
-
- def process_showing():
- if showing_widgets_queue.empty():
- return
-
- widget = showing_widgets_queue.get()
- widget.show()
-
- widget_rect = widget.frameGeometry()
- second_rect = QtCore.QRect(widget_rect)
- second_rect.setTopLeft(second_rect.bottomLeft())
-
- animation = QtCore.QPropertyAnimation(
- widget, b"geometry", self
- )
- animation.setDuration(duration)
- animation.setStartValue(second_rect)
- animation.setEndValue(widget_rect)
- animation.setEasingCurve(QtCore.QEasingCurve.OutQuad)
-
- animation.finished.connect(process_showing)
- animation.start()
-
- def process_hiding():
- if hiding_widgets_queue.empty():
- return process_showing()
-
- item = hiding_widgets_queue.get()
- if isinstance(item, tuple):
- widget = item[0]
- hiding_widgets_queue.put(widget)
- widget_rect = widget.frameGeometry()
- second_rect = QtCore.QRect(widget_rect)
- second_rect.setTopLeft(second_rect.bottomLeft())
-
- anim = QtCore.QPropertyAnimation(
- widget, b"geometry", self
- )
- anim.setDuration(duration)
- anim.setStartValue(widget_rect)
- anim.setEndValue(second_rect)
- anim.setEasingCurve(QtCore.QEasingCurve.OutQuad)
-
- anim.finished.connect(process_hiding)
- anim.start()
- else:
- item.hide()
- return process_hiding()
-
- process_hiding()
-
- def on_validate_clicked(self):
- self.comment_box.setEnabled(False)
- self.footer_items_visibility()
- self.intent_box.setEnabled(False)
-
- self._add_intent_to_context()
-
- self.validate()
-
- def on_play_clicked(self):
- self.comment_box.setEnabled(False)
- self.footer_items_visibility()
- self.intent_box.setEnabled(False)
-
- self._add_intent_to_context()
-
- self.publish()
-
- def on_reset_clicked(self):
- self.reset()
-
- def on_stop_clicked(self):
- self.info("Stopping..")
- self.controller.stop()
-
- # TODO checks
- self.footer_button_reset.setEnabled(True)
- self.footer_button_play.setEnabled(False)
- self.footer_button_stop.setEnabled(False)
-
- def on_suspend_clicked(self, value=None):
- self.apply_log_suspend_value(not self._suspend_logs)
-
- def apply_log_suspend_value(self, value):
- self._suspend_logs = value
- if self._current_page == "terminal":
- self.tabs["overview"].setChecked(True)
-
- self.tabs["terminal"].setVisible(not self._suspend_logs)
-
- def on_comment_entered(self):
- """The user has typed a comment."""
- self.controller.context.data["comment"] = self.comment_box.text()
-
- def on_about_to_process(self, plugin, instance):
- """Reflect currently running pair in GUI"""
- if instance is None:
- instance_id = self.controller.context.id
- else:
- instance_id = instance.id
-
- instance_item = (
- self.instance_model.instance_items[instance_id]
- )
- instance_item.setData(
- {InstanceStates.InProgress: True},
- Roles.PublishFlagsRole
- )
-
- plugin_item = self.plugin_model.plugin_items[plugin._id]
- plugin_item.setData(
- {PluginStates.InProgress: True},
- Roles.PublishFlagsRole
- )
-
- self.info("{} {}".format(
- self.tr("Processing"), plugin_item.data(QtCore.Qt.DisplayRole)
- ))
-
- visibility = True
- if hasattr(plugin, "hide_ui_on_process") and plugin.hide_ui_on_process:
- visibility = False
- self._hidden_for_plugin_process = not visibility
-
- self._ensure_visible(visibility)
-
- def _ensure_visible(self, visible):
- if self.isVisible() == visible:
- return
-
- if not visible:
- self.setVisible(visible)
- else:
- self.show()
- self.raise_()
- self.activateWindow()
- self.showNormal()
-
- def on_plugin_action_menu_requested(self, pos):
- """The user right-clicked on a plug-in
- __________
- | |
- | Action 1 |
- | Action 2 |
- | Action 3 |
- | |
- |__________|
-
- """
-
- index = self.overview_plugin_view.indexAt(pos)
- actions = index.data(Roles.PluginValidActionsRole)
-
- if not actions:
- return
-
- menu = QtWidgets.QMenu(self)
- plugin_id = index.data(Roles.ObjectIdRole)
- plugin_item = self.plugin_model.plugin_items[plugin_id]
- print("plugin is: %s" % plugin_item.plugin)
-
- for action in actions:
- qaction = QtWidgets.QAction(action.label or action.__name__, self)
- qaction.triggered.connect(partial(self.act, plugin_item, action))
- menu.addAction(qaction)
-
- menu.popup(self.overview_plugin_view.viewport().mapToGlobal(pos))
-
- def update_compatibility(self):
- self.plugin_model.update_compatibility()
- self.plugin_proxy.invalidateFilter()
-
- def on_was_reset(self):
- # Append context object to instances model
- self.instance_model.append(self.controller.context)
-
- for plugin in self.controller.plugins:
- self.plugin_model.append(plugin)
-
- self.overview_instance_view.expandAll()
- self.overview_plugin_view.expandAll()
-
- self.presets_button.clearMenu()
- if self.controller.possible_presets:
- self.presets_button.setEnabled(True)
- for key in self.controller.possible_presets:
- self.presets_button.addItem(
- key, partial(self.set_presets, key)
- )
-
- self.instance_model.restore_checkstates()
- self.plugin_model.restore_checkstates()
-
- self.perspective_widget.reset()
-
- # Append placeholder comment from Context
- # This allows users to inject a comment from elsewhere,
- # or to perhaps provide a placeholder comment/template
- # for artists to fill in.
- comment = self.controller.context.data.get("comment")
- self.comment_box.setText(comment or None)
- self.comment_box.setEnabled(True)
- self.footer_items_visibility()
-
- self.intent_box.setEnabled(True)
-
- # Refresh tab
- self.on_tab_changed(self._current_page)
- self.update_compatibility()
-
- self.button_suspend_logs.setEnabled(False)
-
- self.footer_button_validate.setEnabled(False)
- self.footer_button_reset.setEnabled(False)
- self.footer_button_stop.setEnabled(True)
- self.footer_button_play.setEnabled(False)
-
- self._update_state()
-
- def on_passed_group(self, order):
- for group_item in self.instance_model.group_items.values():
- group_index = self.instance_sort_proxy.mapFromSource(
- group_item.index()
- )
- if self.overview_instance_view.isExpanded(group_index):
- continue
-
- if group_item.publish_states & GroupStates.HasError:
- self.overview_instance_view.expand(group_index)
-
- for group_item in self.plugin_model.group_items.values():
- # TODO check only plugins from the group
- if group_item.publish_states & GroupStates.HasFinished:
- continue
-
- if order != group_item.order:
- continue
-
- group_index = self.plugin_proxy.mapFromSource(group_item.index())
- if group_item.publish_states & GroupStates.HasError:
- self.overview_plugin_view.expand(group_index)
- continue
-
- group_item.setData(
- {GroupStates.HasFinished: True},
- Roles.PublishFlagsRole
- )
- self.overview_plugin_view.setAnimated(False)
- self.overview_plugin_view.collapse(group_index)
-
- self._update_state()
-
- def on_was_stopped(self):
- self.overview_plugin_view.setAnimated(settings.Animated)
- errored = self.controller.errored
- if self.controller.collect_state == 0:
- self.footer_button_play.setEnabled(False)
- self.footer_button_validate.setEnabled(False)
- else:
- self.footer_button_play.setEnabled(not errored)
- self.footer_button_validate.setEnabled(
- not errored and not self.controller.validated
- )
- self.footer_button_play.setFocus()
-
- self.footer_button_reset.setEnabled(True)
- self.footer_button_stop.setEnabled(False)
- if errored:
- self.footer_widget.setProperty("success", 0)
- self.footer_widget.style().polish(self.footer_widget)
-
- suspend_log_bool = (
- self.controller.collect_state == 1
- and not self.controller.stopped
- )
- self.button_suspend_logs.setEnabled(suspend_log_bool)
-
- self._update_state()
-
- if self._hidden_for_plugin_process:
- self._hidden_for_plugin_process = False
- self._ensure_visible(True)
-
- def on_was_skipped(self, plugin):
- plugin_item = self.plugin_model.plugin_items[plugin.id]
- plugin_item.setData(
- {PluginStates.WasSkipped: True},
- Roles.PublishFlagsRole
- )
-
- def on_was_finished(self):
- self.overview_plugin_view.setAnimated(settings.Animated)
- self.footer_button_play.setEnabled(False)
- self.footer_button_validate.setEnabled(False)
- self.footer_button_reset.setEnabled(True)
- self.footer_button_stop.setEnabled(False)
-
- if self.controller.errored:
- success_val = 0
- self.info(self.tr("Stopped due to error(s), see Terminal."))
- self.comment_box.setEnabled(False)
- self.intent_box.setEnabled(False)
-
- else:
- success_val = 1
- self.info(self.tr("Finished successfully!"))
-
- self.footer_widget.setProperty("success", success_val)
- self.footer_widget.style().polish(self.footer_widget)
-
- for instance_item in (
- self.instance_model.instance_items.values()
- ):
- instance_item.setData(
- {InstanceStates.HasFinished: True},
- Roles.PublishFlagsRole
- )
-
- for group_item in self.instance_model.group_items.values():
- group_item.setData(
- {GroupStates.HasFinished: True},
- Roles.PublishFlagsRole
- )
-
- self.update_compatibility()
- self._update_state()
-
- def on_was_processed(self, result):
- existing_ids = set(self.instance_model.instance_items.keys())
- existing_ids.remove(self.controller.context.id)
- for instance in self.controller.context:
- if instance.id not in existing_ids:
- self.instance_model.append(instance)
- else:
- existing_ids.remove(instance.id)
-
- for instance_id in existing_ids:
- self.instance_model.remove(instance_id)
-
- result["records"] = self.terminal_model.prepare_records(
- result,
- self._suspend_logs
- )
-
- plugin_item = self.plugin_model.update_with_result(result)
- instance_item = self.instance_model.update_with_result(result)
-
- self.terminal_model.update_with_result(result)
-
- self.update_compatibility()
-
- if self.perspective_widget.isVisible():
- self.perspective_widget.update_context(
- plugin_item, instance_item
- )
-
- if self._hidden_for_plugin_process:
- self._hidden_for_plugin_process = False
- self._ensure_visible(True)
-
- # -------------------------------------------------------------------------
- #
- # Functions
- #
- # -------------------------------------------------------------------------
-
- def reset(self):
- """Prepare GUI for reset"""
- self.info(self.tr("About to reset.."))
-
- self.presets_button.setEnabled(False)
- self.footer_widget.setProperty("success", -1)
- self.footer_widget.style().polish(self.footer_widget)
-
- self.instance_model.store_checkstates()
- self.plugin_model.store_checkstates()
-
- # Reset current ids to secure no previous instances get mixed in.
- self.instance_model.reset()
- self.plugin_model.reset()
- self.intent_model.reset()
- self.terminal_model.reset()
-
- self.footer_button_stop.setEnabled(False)
- self.footer_button_reset.setEnabled(False)
- self.footer_button_validate.setEnabled(False)
- self.footer_button_play.setEnabled(False)
-
- self.intent_box.setVisible(self.intent_model.has_items)
- if self.intent_model.has_items:
- self.intent_box.setCurrentIndex(self.intent_model.default_index)
-
- self.comment_box.placeholder.setVisible(False)
- # Launch controller reset
- self.controller.reset()
- if not self.comment_box.text():
- self.comment_box.placeholder.setVisible(True)
-
- def validate(self):
- self.info(self.tr("Preparing validate.."))
- self.footer_button_stop.setEnabled(True)
- self.footer_button_reset.setEnabled(False)
- self.footer_button_validate.setEnabled(False)
- self.footer_button_play.setEnabled(False)
-
- self.button_suspend_logs.setEnabled(False)
-
- self.controller.validate()
-
- self._update_state()
-
- def publish(self):
- self.info(self.tr("Preparing publish.."))
- self.footer_button_stop.setEnabled(True)
- self.footer_button_reset.setEnabled(False)
- self.footer_button_validate.setEnabled(False)
- self.footer_button_play.setEnabled(False)
-
- self.button_suspend_logs.setEnabled(False)
-
- self.controller.publish()
-
- self._update_state()
-
- def act(self, plugin_item, action):
- self.info("%s %s.." % (self.tr("Preparing"), action))
-
- self.footer_button_stop.setEnabled(True)
- self.footer_button_reset.setEnabled(False)
- self.footer_button_validate.setEnabled(False)
- self.footer_button_play.setEnabled(False)
-
- # Cause view to update, but it won't visually
- # happen until Qt is given time to idle..
- plugin_item.setData(
- PluginActionStates.InProgress, Roles.PluginActionProgressRole
- )
-
- # Give Qt time to draw
- self.controller.act(plugin_item.plugin, action)
-
- self.info(self.tr("Action prepared."))
-
- def on_was_acted(self, result):
- self.footer_button_reset.setEnabled(True)
- self.footer_button_stop.setEnabled(False)
-
- # Update action with result
- plugin_item = self.plugin_model.plugin_items[result["plugin"].id]
- action_state = plugin_item.data(Roles.PluginActionProgressRole)
- action_state |= PluginActionStates.HasFinished
- result["records"] = self.terminal_model.prepare_records(
- result,
- self._suspend_logs
- )
-
- if result.get("error"):
- action_state |= PluginActionStates.HasFailed
-
- plugin_item.setData(action_state, Roles.PluginActionProgressRole)
-
- self.terminal_model.update_with_result(result)
- plugin_item = self.plugin_model.update_with_result(result)
- instance_item = self.instance_model.update_with_result(result)
-
- if self.perspective_widget.isVisible():
- self.perspective_widget.update_context(
- plugin_item, instance_item
- )
-
- def closeEvent(self, event):
- """Perform post-flight checks before closing
-
- Make sure processing of any kind is wrapped up before closing
-
- """
-
- self.info(self.tr("Closing.."))
-
- if self.controller.is_running:
- self.info(self.tr("..as soon as processing is finished.."))
- self.controller.stop()
-
- self.info(self.tr("Cleaning up controller.."))
- self.controller.cleanup()
-
- self.overview_instance_view.setModel(None)
- self.overview_plugin_view.setModel(None)
- self.terminal_view.setModel(None)
-
- event.accept()
-
- def reject(self):
- """Handle ESC key"""
-
- if self.controller.is_running:
- self.info(self.tr("Stopping.."))
- self.controller.stop()
-
- # -------------------------------------------------------------------------
- #
- # Feedback
- #
- # -------------------------------------------------------------------------
-
- def _update_state(self):
- self.footer_info.setText(self.controller.current_state)
-
- def info(self, message):
- """Print user-facing information
-
- Arguments:
- message (str): Text message for the user
-
- """
- # Include message in terminal
- self.terminal_model.append([{
- "label": message,
- "type": "info"
- }])
-
- if settings.PrintInfo:
- # Print message to console
- util.u_print(message)
-
- def warning(self, message):
- """Block processing and print warning until user hits "Continue"
-
- Arguments:
- message (str): Message to display
-
- """
-
- # TODO(marcus): Implement this.
- self.info(message)
-
- def heads_up(self, title, message, command=None):
- """Provide a front-and-center message with optional command
-
- Arguments:
- title (str): Bold and short message
- message (str): Extended message
- command (optional, callable): Function is provided as a button
-
- """
-
- # TODO(marcus): Implement this.
- self.info(message)