[
  {
    "path": ".github/workflows/pypi.yml",
    "content": "# https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions\n# https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/\n\nname: PyPI\non:\n  release:\n    types: [created]\n\njobs:\n  build-and-publish:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - name: Setup Python\n        uses: actions/setup-python@v1\n        with:\n          python-version: '3.x'\n          architecture: x64\n\n      - name: Build wheel\n        run: |\n          pip install --upgrade wheel setuptools\n          python setup.py bdist_wheel\n\n      - name: Publish to PyPI\n        uses: pypa/gh-action-pypi-publish@master\n        with:\n          user: __token__\n          password: ${{ secrets.pypi_password }}\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "# https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions\n\nname: Tests\n\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python-version: ['2.x', '3.x']\n    name: Python ${{ matrix.python-version }}\n    steps:\n      - uses: actions/checkout@v2\n      - name: Setup Python\n        uses: actions/setup-python@v1\n        with:\n          python-version: ${{ matrix.python-version }}\n          architecture: x64\n\n      - name: Build wheel\n        run: |\n          pip install --upgrade wheel setuptools\n          python setup.py bdist_wheel\n\n      - run: pip install isort && isort --recursive --diff .\n      - run: pip install black && black --check .\n        if: matrix.python-version == '3.x'\n      - run: pip install flake8 && flake8\n"
  },
  {
    "path": ".gitignore",
    "content": "# Python\n*.pyc\n\n# Folders\n.eggs\n*.egg-info/\nbuild\ndist\nvenv\n\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n### Version 3.3.0\n\n- adding Blender, 3DS Max, Houdini, and Unreal Engine support\n- see below for installing PySide2 into Blender\n\nUltra Easy Guide To install PySide2 into Blender on macOS:\n\n1) install blender\n2) open blender at least once, and then close blender\n3) open terminal and run the commands below\n```bash\ncurl https://bootstrap.pypa.io/get-pip.py -o get-pip.py\n/Applications/Blender.app/Contents/Resources/2.81/python/bin/python3.7m get-pip.py\n/Applications/Blender.app/Contents/Resources/2.81/python/bin/pip install PySide2, pyvfx-boilerplate\n```\n\nUltra Easy Guide To install PySide into Unreal on Windows:\n\nthis currently fails: (testing on 4.24.2)\n1) install Unreal\n2) open a windows cmd or powershell and run the commands below\n```bash\ncd C:/Program Files/Unreal/UE_4.24/Engine/Binaries/ThirdParty/Python/Win64/\npython.exe -m pip install --upgrade pip\npython.exe -m pip install --no-warn-script-location PySide pyvfx-boilerplate\n```\n\n### Version 3.2.1\n\n- rearrangement of namespace package location\n- updated to setuptools_scm to handle version numbering\n\n### Version 3.2.0\n\n- uses kwargs to pass more arguments to the gui show\n- auto docks into attribute editor panel in maya if dockable=True in kwargs\n\n### Version 3.1.0\n\n#### Changes from 2.0 (nzanepro fork)\n\n- Updated to work with latest Qt.py (1.2.0b2)\n- Tested with maya (2018.4), nuke (11.2v4), and PySide2 (5.11.2)\n- Install via pip and you will get Qt.py installed as a dependency (see below)\n- Now includes MayaQWidgetDockableMixin in maya\n- Better Maya menuing via python instead of pymel, pyvfx now has a root menu, and other modules can be added to the menu.\n\n- Example new app via inheritance of Boilerplate (includes extension of MayaQWidgetDockableMixin):\n\nhttps://github.com/nzanepro/pyvfx.boilerplateinherited\n\n#### Changes from 1.0\n\n- Complete rewrite of the boilerplate.\n- Requires (and bundles) the [`Qt.py`](https://github.com/mottosso/Qt.py)\n- Tested with Python 2.7.11 and 3.5.1.\n- Uses `PySide.QUiTools` instead of `pysideuic`, which was used in v1.0.\n- No longer uses the complex \"wrap instance\" approach in favor for simpler code. Because of this, UIs are no longer loaded into `self`.\n- Maya palette styling in standalone mode.\n- Git repo name change: all lowercase.\n- Pretty much PEP8 compliant.\n- Properly parented window in Maya\n- Writing of .pyc (bytecode) files disabled to prevent issues between Python 2 and 3.\n- Can be run in multiple ways (see examples).\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Fredrik Averpil\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "# pyvfx-boilerplate\n\n![Tests](https://github.com/fredrikaverpil/pyvfx-boilerplate/workflows/Tests/badge.svg) ![PyPI](https://github.com/fredrikaverpil/pyvfx-boilerplate/workflows/PyPI/badge.svg)\n\nA boilerplate for creating PyQt4/PySide and PyQt5/PySide2 applications running in Maya, Nuke, Blender, 3DS Max, Houdini, Unreal Engine or completely standalone.\n\n## Documentation\n\n### Version 3.x\n\n- The entire boilerplate was re-written so it could be packaged and distributed with PyPi.\n- Adding Blender, 3DS Max, Houdini, and Unreal Engine support.\n\nFor details, see [CHANGELOG.md](CHANGELOG.md).\n\n### Noteworthy known issues\n\n- Does not work with Nuke 10.0v1 on OS X: [#7](https://github.com/fredrikaverpil/pyvfx-boilerplate/issues/7)\n- Maya palette glitchy in standalone mode with PySide/PyQt4 on OS X (disabled by default): [#9](https://github.com/fredrikaverpil/pyvfx-boilerplate/issues/9)\n- Window will not stay on top of Nuke (OS X) without Qt.Tool or Qt.WindowStaysOnTopHint: [#12](https://github.com/fredrikaverpil/pyvfx-boilerplate/issues/12)\n### Installation\n\nEasy way:\n\n```bash\npip install pyvfx-boilerplate\n```\n\nLong way:\n\n```bash\ngit clone https://github.com/fredrikaverpil/pyvfx-boilerplate.git\ncd pyvfx-boilerplate\npython setup.py sdist bdist_wheel\npip install dist/*\n```\n\n### Example usage\n\nPip installs a program named `pyvfx-boilerplate` as an example Run as standalone:\n(you may need to additionally install PyQt4, PyQt5, PySide or PySide2 for standalone to work depending on your system configuration)\n\n```bash\npyvfx-boilerplate\n```\n\nRun in script editor of Maya or Nuke:\n\n```python\nimport sys\nsys.path.append('/path/to/pyvfx-boilerplate')\nfrom pyvfx_boilerplate import boilerplate_ui\nbpr = boilerplate_ui.BoilerplateRunner()\nbpr.run_main()\n```\n\n### Modifying the boilerplate\n\n- See inheritance example above\n\n### Development guidelines\n\nSince the boilerplate relies on [`Qt.py`](https://github.com/mottosso/Qt.py), you should design your application as if you were designing it for PyQt5/PySide2. This means creating widgets using `QtWidgets` rather than `QtGui`. The `Qt.py` module takes care of the remapping and makes for compatibility with PyQt4/PySide. Read more over at the [`Qt.py` repository](https://github.com/mottosso/Qt.py).\n\nTip: when you cannot rely on `Qt.py`, create an issue (probably over at [`Qt.py`](https://github.com/mottosso/Qt.py)) and/or detect which binding is being used and write some custom code:\n\n```python\nfrom Qt import QtCompat\n\nif QtCompat.__binding__ in ('PyQt4', 'PySide'):\n    # Do something if PyQt4 or PySide is used\n\nif QtCompat__binding.startswith('PySide'):\n    # Do something if PySide or PySide2 is used\n\nif QtCompat__binding == 'PySide2':\n    # Do something if PySide2 is used\n```\n\n### Issues\n\nSomething wrong, have a question or wish to file a feature request?\n\nOpen up an issue [here](https://github.com/fredrikaverpil/pyvfx-boilerplate/issues)!\n\n### Contribute\n\nIf you wish to contribute, pull requests are more than welcome!\n"
  },
  {
    "path": "setup.cfg",
    "content": "[bdist_wheel]\nuniversal=1"
  },
  {
    "path": "setup.py",
    "content": "# https://docs.python.org/3/distutils/setupscript.html#additional-meta-data\n\nimport setuptools\n\nwith open(\"README.md\", \"r\") as fh:\n    long_description = fh.read()\n\nname = \"pyvfx-boilerplate\"\nurl = \"https://github.com/fredrikaverpil/pyvfx-boilerplate\"\ndescription = \"A boilerplate Qt Py* app that runs in dcc apps, py2, or py3.\"\npackage_dir = \"src\"\ncli_modules = [\n    \"pyvfx-boilerplate=pyvfx_boilerplate.cli:main\",\n]\n\nsetuptools.setup(\n    setup_requires=[\"setuptools_scm\"],\n    use_scm_version={\"local_scheme\": \"node-and-timestamp\"},\n    name=name,\n    description=description,\n    long_description=long_description,\n    long_description_content_type=\"text/markdown\",\n    url=url,\n    packages=setuptools.find_packages(package_dir),\n    package_dir={\"\": package_dir},\n    entry_points={\"console_scripts\": cli_modules},\n    include_package_data=True,\n    install_requires=[\"Qt.py\"],\n    classifiers=[\n        \"Programming Language :: Python :: 2.7\",\n        \"Programming Language :: Python :: 3.7\",\n        \"License :: OSI Approved :: MIT License\",\n        \"Operating System :: OS Independent\",\n    ],\n)\n"
  },
  {
    "path": "src/pyvfx_boilerplate/__init__.py",
    "content": "__path__ = __import__(\"pkgutil\").extend_path(__path__, __name__)\n"
  },
  {
    "path": "src/pyvfx_boilerplate/boilerplate_ui.py",
    "content": "\"\"\"This uses a Qt binding of \"any\" kind, thanks to the Qt.py module,\nto produce an UI. First, one .ui file is loaded and then attaches\nanother .ui file onto the first. Think of it as creating a modular UI.\n\nMore on Qt.py:\nhttps://github.com/mottosso/Qt.py\n\"\"\"\n\nimport atexit\nimport os\nimport platform\nimport sys\n\nimport Qt\nfrom Qt import QtCompat, QtCore, QtWidgets  # pylint: disable=E0611\n\nfrom . import mayapalette\n\ntry:\n    import maya.cmds as cmds\n    from maya.app.general.mayaMixin import MayaQWidgetDockableMixin\n\n    MAYA = True\nexcept ImportError:\n    MAYA = False\n\ntry:\n    import nuke\n    import nukescripts\n\n    NUKE = True\nexcept ImportError:\n    NUKE = False\n\ntry:\n    import hou\n\n    HOUDINI = True\nexcept ImportError:\n    HOUDINI = False\n\ntry:\n    import MaxPlus\n\n    THREEDSMAX = True\nexcept ImportError:\n    THREEDSMAX = False\n\ntry:\n    import bpy\n\n    BLENDER = True\nexcept ImportError:\n    BLENDER = False\n\ntry:\n    import unreal\n\n    UNREAL = True\nexcept ImportError:\n    UNREAL = False\n\n# ----------------------------------------------------------------------\n# Configuration\n# ----------------------------------------------------------------------\n\n# Full path to where .ui files are stored\nUI_PATH = os.path.join(os.path.dirname(__file__), \"resources\")\n\n# Palette filepath\nPALETTE_FILEPATH = os.path.join(UI_PATH, \"qpalette_maya2016.json\")\nWTITLE = \"Boilerplate\"\nWOBJ = \"boilerPlate\"\n\n# ----------------------------------------------------------------------\n# Main script\n# ----------------------------------------------------------------------\n\n\nclass _Boilerplate(QtWidgets.QMainWindow):\n    \"\"\"\n    Don't subclass this directly, subclass Boilerplate without the '_'\n    \"\"\"\n\n    def __init__(self, parent=None, win_title=WTITLE, win_object=WOBJ):\n\n        super(_Boilerplate, self).__init__(parent)\n\n        # Set object name and window title\n        self.setObjectName(win_object)\n        self.setWindowTitle(win_title)\n\n        # Window type\n        self.setWindowFlags(QtCore.Qt.Window)\n\n        if MAYA:\n            # Makes Maya perform magic which makes the window stay\n            # on top in OS X and Linux. As an added bonus, it'll\n            # make Maya remember the window position\n            self.setProperty(\"saveWindowPref\", True)\n\n        self.setupUi()\n\n    def setupUi(self):\n        # Filepaths\n        main_window_file = os.path.join(UI_PATH, \"main_window.ui\")\n        module_file = os.path.join(UI_PATH, \"module.ui\")\n\n        # Load UIs\n        self.main_widget = QtCompat.load_ui(main_window_file)  # Main window UI\n        self.module_widget = QtCompat.load_ui(module_file)  # Module UI\n\n        # Attach module to main window UI's boilerVerticalLayout layout\n        self.main_widget.boilerVerticalLayout.addWidget(self.module_widget)\n\n        # Edit widget which resides in module UI\n        self.module_widget.boilerLabel.setText(\"Push the button!\")\n\n        # Edit widget which reside in main window UI\n        self.main_widget.boilerPushButton.setText(\"Push me!\")\n\n        # Set the main widget\n        self.setCentralWidget(self.main_widget)\n\n        # Define minimum size of UI\n        self.setMinimumSize(200, 200)\n\n        # Signals\n        # The \"pushButton\" widget resides in the main window UI\n        self.main_widget.boilerPushButton.clicked.connect(self.say_hello)\n\n    def say_hello(self):\n        \"\"\"Set the label text.\n        The \"label\" widget resides in the module\n        \"\"\"\n        self.module_widget.boilerLabel.setText(\"Hello world!\")\n        self.module_widget.boilerLabel.update()\n\n\nif MAYA:\n\n    class Boilerplate(MayaQWidgetDockableMixin, _Boilerplate):\n        \"\"\"Example showing how UI files can be loaded using the same script\n        when taking advantage of the Qt.py module and build-in methods\n        from PySide/PySide2/PyQt4/PyQt5.\"\"\"\n\n        def __init__(self, parent=None, win_title=WTITLE, win_object=WOBJ):\n            super(Boilerplate, self).__init__(\n                parent, win_title=win_title, win_object=win_object\n            )\n\n\n# elif THREEDSMAX:\n#     # https://forums.autodesk.com/t5/3ds-max-programming/3ds-max-2019-qt-dock-widget/td-p/8164550 # noqa\n#     # https://help.autodesk.com/view/3DSMAX/2019/ENU/?guid=__py_ref_demo_py_side_tool_bar_q_widget_8py_example_html # noqa\n#     pass\nelse:\n\n    class Boilerplate(_Boilerplate):\n        \"\"\"Example showing how UI files can be loaded using the same script\n        when taking advantage of the Qt.py module and build-in methods\n        from PySide/PySide2/PyQt4/PyQt5.\"\"\"\n\n        def __init__(self, parent=None, win_title=WTITLE, win_object=WOBJ):\n            super(Boilerplate, self).__init__(\n                parent, win_title=win_title, win_object=win_object\n            )\n\n\n# ----------------------------------------------------------------------\n# DCC application helper functions\n# ----------------------------------------------------------------------\ndef _maya_delete_ui(window_title, window_object):\n    \"\"\"Delete existing UI in Maya\"\"\"\n    if cmds.window(window_object, q=True, exists=True):\n        cmds.deleteUI(window_object)  # Delete window\n    if cmds.dockControl(\"MayaWindow|\" + window_title, q=True, ex=True):\n        cmds.deleteUI(\"MayaWindow|\" + window_title)  # Delete docked window\n\n\ndef _maya_delete_workspace(window_object):\n    \"\"\"Delete existing workspace in Maya\"\"\"\n    control = window_object + \"WorkspaceControl\"\n    if cmds.workspaceControl(control, q=True, exists=True):\n        cmds.workspaceControl(control, e=True, close=True)\n        cmds.deleteUI(control, control=True)\n\n\ndef _maya_update_workspace(window_object):\n    \"\"\"Updates existing workspace in Maya\"\"\"\n    control = window_object + \"WorkspaceControl\"\n    # TODO make this argument controllable\n    if cmds.workspaceControl(control, q=True, exists=True):\n        cmds.workspaceControl(\n            control,\n            e=True,\n            restore=True,\n            retain=True,\n            # # options below\n            # dockToMainWindow=(\"left\", -1),\n            # tabToControl=(\"ChannelBoxLayerEditor\", -1),\n            # tabToControl=(\"Outliner\", -1),\n            tabToControl=(\"AttributeEditor\", -1),\n        )\n\n\ndef _maya_main_window():\n    \"\"\"Return Maya's main window\"\"\"\n    for obj in QtWidgets.QApplication.topLevelWidgets():\n        if obj.objectName() == \"MayaWindow\":\n            return obj\n    raise RuntimeError(\"Could not find MayaWindow instance\")\n\n\ndef _nuke_delete_ui(window_object):\n    \"\"\"Delete existing UI in Nuke\"\"\"\n    for obj in QtWidgets.QApplication.allWidgets():\n        if obj.objectName() == window_object:\n            obj.deleteLater()\n\n\ndef _nuke_main_window():\n    \"\"\"Returns Nuke's main window\"\"\"\n    for obj in QtWidgets.QApplication.topLevelWidgets():\n        if (\n            obj.inherits(\"QMainWindow\")\n            and obj.metaObject().className() == \"Foundry::UI::DockMainWindow\"\n        ):\n            return obj\n    else:\n        raise RuntimeError(\"Could not find DockMainWindow instance\")\n\n\ndef _nuke_set_zero_margins(widget_object):\n    \"\"\"Remove Nuke margins when docked UI\n\n    .. _More info:\n        https://gist.github.com/maty974/4739917\n    \"\"\"\n    parentApp = QtWidgets.QApplication.allWidgets()\n    parentWidgetList = []\n    for parent in parentApp:\n        for child in parent.children():\n            if widget_object.__class__.__name__ == child.__class__.__name__:\n                parentWidgetList.append(parent.parentWidget())\n                try:\n                    twoup = parent.parentWidget().parentWidget()\n                    parentWidgetList.append(twoup)\n                    threeup = twoup.parentWidget()\n                    parentWidgetList.append(threeup)\n                except AttributeError:\n                    pass\n\n                for sub in parentWidgetList:\n                    if sub is not None:\n                        for tinychild in sub.children():\n                            try:\n                                tinychild.setContentsMargins(0, 0, 0, 0)\n                            except AttributeError:\n                                pass\n\n\ndef _houdini_main_window():\n    \"\"\"Return Houdini's main window\"\"\"\n    return hou.ui.mainQtWindow()\n\n\ndef _3dsmax_main_window():\n    \"\"\"Return 3dsmax's main window\"\"\"\n    return MaxPlus.GetQMaxMainWindow()\n\n\n# ----------------------------------------------------------------------\n# Run functions\n# ----------------------------------------------------------------------\nclass BoilerplateRunner:\n    def __init__(self, guiClass=Boilerplate, win_title=WTITLE, win_object=WOBJ):  # noqa\n\n        self.guiClass = guiClass\n        self.window_title = win_title\n        self.window_object = win_object\n        self.boil = None\n\n    def run_maya(self, **kwargs):\n        \"\"\"Run in Maya\"\"\"\n        # Delete any existing existing UI\n        _maya_delete_ui(self.window_title, self.window_object)\n        # Delete any existing existing workspace\n        _maya_delete_workspace(self.window_object)\n        self.boil = self.guiClass(\n            _maya_main_window(), self.window_title, self.window_object\n        )\n\n        # Makes Maya perform magic which makes the window stay\n        # on top in OS X and Linux. As an added bonus, it'll\n        # make Maya remember the window position\n        self.boil.setProperty(\"saveWindowPref\", True)\n\n        if \"dockable\" in kwargs and kwargs[\"dockable\"]:\n            kwargs[\"allowed_areas\"] = [\"right\", \"left\"]\n        self.boil.show(**kwargs)\n        if \"dockable\" in kwargs and kwargs[\"dockable\"]:\n            _maya_update_workspace(self.window_object)\n\n    def run_nuke(self, **kwargs):\n        \"\"\"Run in Nuke\n\n        Note:\n            If you want the UI to always stay on top, replace:\n            `boil.ui.setWindowFlags(QtCore.Qt.Tool)`\n            with:\n            `boil.ui.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)`\n\n            If you want the UI to be modal:\n            `boil.ui.setWindowModality(QtCore.Qt.WindowModal)`\n        \"\"\"\n        _nuke_delete_ui(self.window_object)  # Delete any alrady existing UI\n        if \"dockable\" in kwargs and kwargs[\"dockable\"]:\n            widgetname = (\"{}.{}\").format(\n                self.guiClass.__module__, self.guiClass.__name__\n            )\n            panel = nukescripts.panels.registerWidgetAsPanel(\n                widget=widgetname,  # module_name.Class_name\n                name=self.window_title,\n                id=\"uk.co.thefoundry.\" + self.window_title,\n                create=True,\n            )\n            pane = nuke.getPaneFor(\"Properties.1\")\n            panel.addToPane(pane)\n            self.boil = panel.customKnob.getObject().widget\n            _nuke_set_zero_margins(self.boil)\n        else:\n            self.boil = self.guiClass(\n                _nuke_main_window(), self.window_title, self.window_object\n            )\n            self.boil.setWindowFlags(QtCore.Qt.Tool)\n            self.boil.show()  # Show the UI\n\n    def run_houdini(self, **kwargs):\n        \"\"\"Run in Houdini\"\"\"\n        self.boil = self.guiClass(\n            _houdini_main_window(), self.window_title, self.window_object\n        )\n        self.boil.show()\n\n    def run_3dsmax(self, **kwargs):\n        \"\"\"Run in 3dsmax\"\"\"\n        # https://gist.github.com/mrabito/0f9d1f177a3bea94d33d35b476c88731\n        # dockable?\n        # https://help.autodesk.com/view/3DSMAX/2019/ENU/?guid=__py_ref_demo_py_side_tool_bar_q_widget_8py_example_html\n        self.boil = self.guiClass(\n            _3dsmax_main_window(), self.window_title, self.window_object\n        )\n        self.boil.show()\n\n    def on_exit_unreal(self):\n        app = QtWidgets.QApplication.instance()\n        if app:\n            app.store_window_geometry()\n            app.quit()\n\n    def run_unreal(self, **kwargs):\n        # https://github.com/20tab/UnrealEnginePython\n        # https://forums.unrealengine.com/development-discussion/python-scripting/1674204-dock-qtwidget-to-unreal\n        # https://github.com/AlexQuevillon/UnrealPythonLibrary/blob/master/UnrealProject/UnrealPythonLibrary/Plugins/UnrealPythonLibraryPlugin/Content/Python/PythonLibraries/QtFunctions.py\n        # https://forums.unrealengine.com/unreal-engine/unreal-studio/1526501-how-to-get-the-main-window-of-the-editor-to-parent-qt-or-pyside-application-to-it\n        app = QtWidgets.QApplication.instance()\n\n        if not app:\n            # create the first instance\n            app = QtWidgets.QApplication(sys.argv)\n            app.aboutToQuit.connect(self.on_exit_unreal)\n\n        atexit.register(self.on_exit_unreal)\n\n        self.boil = None\n\n        self.event_loop = QtCore.QEventLoop()\n        self.boil = self.guiClass(None, self.window_title, self.window_object)\n        mayapalette.set_maya_palette_with_tweaks(PALETTE_FILEPATH)\n        unreal.parent_external_window_to_slate(self.boil.winId())\n        self.boil.show()\n\n    def on_exit_blender(self):\n        \"\"\"\n        Close BlenderApplication instance on exit\n\n        Returns: None\n\n        \"\"\"\n        app = QtWidgets.QApplication.instance()\n        if app:\n            app.store_window_geometry()\n            app.quit()\n\n    def on_update_blender(self):\n        # https://github.com/techartorg/bqt\n        app = QtWidgets.QApplication.instance()\n        if app.should_close:\n            win = bpy.context.window_manager.windows[0]\n            bpy.ops.wm.quit_blender({\"window\": win}, \"INVOKE_DEFAULT\")\n\n    def run_blender(self, **kwargs):\n        \"\"\"Run in Blender\"\"\"\n        # mix of code from\n        # https://github.com/friedererdmann/blender_pyside2_example\n        # and\n        # https://github.com/techartorg/bqt\n\n        # TODO add dockable?\n        # https://github.com/cube-creative/guibedos/blob/master/guibedos/blender.py\n        app = QtWidgets.QApplication.instance()\n\n        if not app:\n            # create the first instance\n            app = QtWidgets.QApplication(sys.argv)\n            # modal\n            bpy.app.timers.register(self.on_update_blender, persistent=True)\n\n        atexit.register(self.on_exit_blender)\n\n        self.event_loop = QtCore.QEventLoop()\n        self.boil = self.guiClass(None, self.window_title, self.window_object)\n        mayapalette.set_maya_palette_with_tweaks(PALETTE_FILEPATH)\n        self.boil.show()\n        # non-modal:\n        # app.exec_()\n\n    def run_standalone(self, **kwargs):\n        \"\"\"Run standalone\n\n        Note:\n            Styling the UI with the Maya palette on OS X when using the\n            PySide/PyQt4 bindings result in various issues, which is why\n            it is disabled by default when you're running this combo.\n\n        .. _Issue #9:\n           https://github.com/fredrikaverpil/pyvfx-boilerplate/issues/9\n        \"\"\"\n        extrawin = True\n        app = QtWidgets.QApplication.instance()\n\n        if not app:\n            app = QtWidgets.QApplication(sys.argv)\n            extrawin = False\n\n        self.boil = self.guiClass(\n            win_title=self.window_title, win_object=self.window_object\n        )\n        if not (platform.system() == \"Darwin\" and (Qt.IsPySide or Qt.IsPyQt4)):\n            mayapalette.set_maya_palette_with_tweaks(PALETTE_FILEPATH)\n        self.boil.show()  # Show the UI\n\n        if not extrawin:\n            sys.exit(app.exec_())\n\n    def run_main(self, **kwargs):\n        \"\"\"Run appropriate gui\"\"\"\n        if MAYA:\n            self.run_maya(**kwargs)\n        elif NUKE:\n            self.run_nuke(**kwargs)\n        elif HOUDINI:\n            self.run_houdini(**kwargs)\n        elif THREEDSMAX:\n            self.run_3dsmax(**kwargs)\n        elif BLENDER:\n            self.run_blender(**kwargs)\n        elif UNREAL:\n            self.run_unreal(**kwargs)\n        else:\n            self.run_standalone(**kwargs)\n"
  },
  {
    "path": "src/pyvfx_boilerplate/cli.py",
    "content": "#!/usr/bin/env python\nimport os\nimport sys\n\n# this is required to keep pyside2 seperate from maya and nuke's pyside2\n# make sure this is added to any inherited program to work from cli\nif \"QT_PREFERRED_PATH\" in os.environ:\n    sys.path.append(os.environ[\"QT_PREFERRED_PATH\"])\n\nfrom pyvfx_boilerplate import menu  # isort:skip\n\n\ndef main():\n    menu.activate()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "src/pyvfx_boilerplate/init.py",
    "content": ""
  },
  {
    "path": "src/pyvfx_boilerplate/mayapalette.py",
    "content": "import json\n\nfrom Qt import QtGui, QtWidgets\n\n\ndef set_palette_from_dict(dct):\n    \"\"\"Set palette to current QApplication based on given dictionary\"\"\"\n    groups = [\"Disabled\", \"Active\", \"Inactive\", \"Normal\"]\n    roles = [\n        \"AlternateBase\",\n        \"Background\",\n        \"Base\",\n        \"Button\",\n        \"ButtonText\",\n        \"BrightText\",\n        \"Dark\",\n        \"Foreground\",\n        \"Highlight\",\n        \"HighlightedText\",\n        \"Light\",\n        \"Link\",\n        \"LinkVisited\",\n        \"Mid\",\n        \"Midlight\",\n        \"Shadow\",\n        \"ToolTipBase\",\n        \"ToolTipText\",\n        \"Text\",\n        \"Window\",\n        \"WindowText\",\n    ]\n    palette = QtGui.QPalette()\n    for role in roles:\n        try:\n            for group in groups:\n                color = QtGui.QColor(dct[\"%s:%s\" % (role, group)])\n                qGrp = getattr(QtGui.QPalette, group)\n                qRl = getattr(QtGui.QPalette, role)\n                palette.setColor(qGrp, qRl, color)\n        except:  # noqa\n            print(\"Could not use: \" + str(palette))\n    try:\n        QtWidgets.QApplication.setPalette(palette)\n    except:  # noqa\n        print(\"Could not set palette: \" + str(palette))\n\n\ndef set_style():\n    \"\"\"Set style\"\"\"\n    available_styles = QtWidgets.QStyleFactory.keys()\n    if \"Fusion\" in available_styles:\n        QtWidgets.QApplication.setStyle(\"Fusion\")\n    elif \"Plastique\" in available_styles:\n        QtWidgets.QApplication.setStyle(\"Plastique\")\n\n\ndef set_maya_tweaks():\n    \"\"\"Apply Maya-specific styling\"\"\"\n    base_palette = QtWidgets.QApplication.palette()\n\n    # Set custom colors\n    LIGHT_COLOR = QtGui.QColor(100, 100, 100)\n    MID_COLOR = QtGui.QColor(68, 68, 68)\n\n    # Create a new palette\n    tab_palette = QtGui.QPalette(base_palette)\n    tab_palette.setBrush(QtGui.QPalette.Window, QtGui.QBrush(LIGHT_COLOR))\n    tab_palette.setBrush(QtGui.QPalette.Button, QtGui.QBrush(MID_COLOR))\n\n    # Define the widgets that needs tweaking\n    widget_palettes = {}\n    widget_palettes[\"QTabBar\"] = tab_palette\n    widget_palettes[\"QTabWidget\"] = tab_palette\n\n    # Set the new tweaked palette\n    for name, palette in widget_palettes.items():\n        QtWidgets.QApplication.setPalette(palette, name)\n\n\ndef read_json(filepath):\n    \"\"\"Read given JSON filepath into dictionary\"\"\"\n    with open(filepath, \"r\") as data_file:\n        data = json.load(data_file)\n    return data\n\n\ndef set_maya_palette_with_tweaks(palette_filepath):\n    \"\"\"Apply styling to current QApplication\"\"\"\n    data = read_json(palette_filepath)\n    set_palette_from_dict(data)\n    set_style()\n    set_maya_tweaks()\n"
  },
  {
    "path": "src/pyvfx_boilerplate/menu.py",
    "content": "import pyvfx_boilerplate.boilerplate_ui as bpui\n\ntry:\n    import maya.cmds as cmds\n    import maya.mel as mel\n\n    MAYA = True\nexcept ImportError:\n    MAYA = False\n\ntry:\n    import nuke\n\n    NUKE = True\nexcept ImportError:\n    NUKE = False\n\ntry:\n    import hou  # noqa\n\n    HOUDINI = True\nexcept ImportError:\n    HOUDINI = False\n\ntry:\n    import MaxPlus\n\n    THREEDSMAX = True\nexcept ImportError:\n    THREEDSMAX = False\n\ntry:\n    import bpy\n\n    BLENDER = True\nexcept ImportError:\n    BLENDER = False\n\ntry:\n    import unreal  # noqa\n\n    UNREAL = True\nexcept ImportError:\n    UNREAL = False\n\n\nrootMenuName = \"pyvfx\"\n\n\ndef activate(dockable=False):\n    bpr = bpui.BoilerplateRunner(bpui.Boilerplate)\n    kwargs = {}\n    kwargs[\"dockable\"] = dockable\n    bpr.run_main(**kwargs)\n\n\nmcmd = \"import pyvfx_boilerplate.menu\\npyvfx_boilerplate.menu.activate({})\"\nif NUKE:\n    m = nuke.menu(\"Nuke\")\n    menuname = \"{}/boilerplate UI\".format(rootMenuName)\n    m.addCommand(\"{}/boilerplate UI\".format(rootMenuName), mcmd.format(\"\"))\n    m.addCommand(\"{} dockable\".format(menuname), mcmd.format(\"True\"))\n\nelif MAYA:\n    MainMayaWindow = mel.eval(\"$temp = $gMainWindow\")\n    if not cmds.menu(\"pyvfxMenuItemRoot\", exists=True):\n        cmds.menu(\n            \"pyvfxMenuItemRoot\",\n            label=rootMenuName,\n            parent=MainMayaWindow,\n            tearOff=True,\n            allowOptionBoxes=True,\n        )\n\n    cmds.menuItem(\n        label=\"boilerplate UI\",\n        parent=\"pyvfxMenuItemRoot\",\n        ec=True,\n        command=mcmd.format(\"\"),\n    )\n\n    cmds.menuItem(\n        label=\"boilerplate UI dockable\",\n        parent=\"pyvfxMenuItemRoot\",\n        ec=True,\n        command=mcmd.format(\"True\"),\n    )\n\nelif HOUDINI:\n    print(\"add menu code here for Houdini\")\n    activate()\n\nelif UNREAL:\n    # http://golaem.com/content/doc/golaem-crowd-documentation/rendering-unreal-engine\n    # https://github.com/AlexQuevillon/UnrealPythonLibrary/tree/master/UnrealProject/UnrealPythonLibrary\n    print(\"add menu code here for Unreal\")\n    activate()\n\nelif THREEDSMAX:\n\n    def activate_dockable():\n        activate(True)\n\n    MaxPlus.MenuManager.UnregisterMenu(rootMenuName)\n    mb = MaxPlus.MenuBuilder(rootMenuName)\n    menuitem = \"boilerplate UI\"\n    menuitemD = \"{} dockable\".format(menuitem)\n    menulist = [\n        (menuitem, menuitem, activate),\n        (menuitemD, menuitemD, activate_dockable),\n    ]\n    for item in menulist:\n        action = MaxPlus.ActionFactory.Create(item[0], item[1], item[2])\n        mb.AddItem(action)\n    menu = mb.Create(MaxPlus.MenuManager.GetMainMenu())\n\nelif BLENDER:\n    # a little of This\n    # https://blender.stackexchange.com/questions/156652/topbar-ht-upper-bar-append-add-menus-in-two-places\n    # and a little of this\n    # https://blenderartists.org/t/creating-a-custom-menu-option/627316/4\n\n    class PyvfxBoilerplateActivateOperator(bpy.types.Operator):\n        \"\"\"start the pyvfx_boilerplate ui\"\"\"\n\n        bl_idname = \"pyvfx_boilerplate_activate\"\n        bl_label = \"boilerplate UI\"\n\n        def execute(self, context):\n            activate()\n            return {\"FINISHED\"}\n\n    class TOPBAR_MT_pyvfx_menu(bpy.types.Menu):\n        \"\"\"create the pyvfx top menu and pyvfx menu item\"\"\"\n\n        bl_label = rootMenuName\n\n        def draw(self, context):\n            \"\"\"create the pyvfx menu item\"\"\"\n            layout = self.layout\n            layout.operator(\"pyvfx_boilerplate_activate\")\n\n        def menu_draw(self, context):\n            \"\"\"create the pyvfx top menu\"\"\"\n            self.layout.menu(\"TOPBAR_MT_pyvfx_menu\")\n\n    def register():\n        bpy.utils.register_class(PyvfxBoilerplateActivateOperator)\n        bpy.utils.register_class(TOPBAR_MT_pyvfx_menu)\n        bpy.types.TOPBAR_MT_editor_menus.append(TOPBAR_MT_pyvfx_menu.menu_draw)\n\n    def unregister():\n        bpy.utils.unregister_class(PyvfxBoilerplateActivateOperator)\n        bpy.types.TOPBAR_MT_editor_menus.remove(TOPBAR_MT_pyvfx_menu.menu_draw)\n        bpy.utils.unregister_class(TOPBAR_MT_pyvfx_menu)\n\n    register()\n\nelse:\n    activate()\n"
  },
  {
    "path": "src/pyvfx_boilerplate/resources/main_window.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>405</width>\n    <height>348</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>MainWindow</string>\n  </property>\n  <widget class=\"QWidget\" name=\"centralwidget\">\n   <layout class=\"QGridLayout\" name=\"gridLayout\">\n    <item row=\"0\" column=\"0\">\n     <layout class=\"QVBoxLayout\" name=\"boilerVerticalLayout\">\n      <item>\n       <widget class=\"QPushButton\" name=\"boilerPushButton\">\n        <property name=\"text\">\n         <string>PushButton</string>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </item>\n   </layout>\n  </widget>\n  <widget class=\"QStatusBar\" name=\"statusbar\"/>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "src/pyvfx_boilerplate/resources/module.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>Form</class>\n <widget class=\"QWidget\" name=\"Form\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>300</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Form</string>\n  </property>\n  <layout class=\"QGridLayout\" name=\"gridLayout\">\n   <item row=\"0\" column=\"0\">\n    <widget class=\"QFrame\" name=\"frame\">\n     <property name=\"frameShape\">\n      <enum>QFrame::StyledPanel</enum>\n     </property>\n     <property name=\"frameShadow\">\n      <enum>QFrame::Raised</enum>\n     </property>\n     <layout class=\"QGridLayout\" name=\"gridLayout_2\">\n      <item row=\"0\" column=\"0\">\n       <widget class=\"QLabel\" name=\"boilerLabel\">\n        <property name=\"text\">\n         <string>TextLabel</string>\n        </property>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "src/pyvfx_boilerplate/resources/qpalette_maya2015.json",
    "content": "{\n  \"Foreground:Active\": 4291348680,\n  \"HighlightedText:Active\": 4294967295,\n  \"Mid:Active\": 4281150765,\n  \"WindowText:Normal\": 4291348680,\n  \"Window:Disabled\": 4282664004,\n  \"AlternateBase:Inactive\": 4281216558,\n  \"Midlight:Normal\": 4282071867,\n  \"HighlightedText:Inactive\": 4294967295,\n  \"Text:Disabled\": 4285098345,\n  \"Midlight:Disabled\": 4282071867,\n  \"Midlight:Inactive\": 4282071867,\n  \"Highlight:Disabled\": 4283856276,\n  \"Base:Disabled\": 4280953386,\n  \"Window:Active\": 4282664004,\n  \"Background:Inactive\": 4282664004,\n  \"AlternateBase:Disabled\": 4281216558,\n  \"Button:Inactive\": 4284769380,\n  \"AlternateBase:Active\": 4281216558,\n  \"LinkVisited:Active\": 4283570315,\n  \"ToolTipBase:Inactive\": 4294967260,\n  \"Dark:Inactive\": 4280624421,\n  \"LinkVisited:Inactive\": 4283570315,\n  \"Dark:Disabled\": 4280624421,\n  \"Light:Inactive\": 4284572001,\n  \"ButtonText:Inactive\": 4291348680,\n  \"Dark:Active\": 4280624421,\n  \"Light:Disabled\": 4284572001,\n  \"Button:Disabled\": 4283453520,\n  \"Shadow:Inactive\": 4278190080,\n  \"ToolTipBase:Disabled\": 4294967260,\n  \"BrightText:Inactive\": 4280624421,\n  \"ToolTipBase:Active\": 4294967260,\n  \"Highlight:Active\": 4284976562,\n  \"BrightText:Disabled\": 4294967295,\n  \"Highlight:Inactive\": 4284976562,\n  \"ToolTipText:Active\": 4278190080,\n  \"Light:Active\": 4284572001,\n  \"Button:Active\": 4284769380,\n  \"ButtonText:Disabled\": 4286611584,\n  \"HighlightedText:Normal\": 4294967295,\n  \"Base:Inactive\": 4280953386,\n  \"BrightText:Active\": 4280624421,\n  \"Highlight:Normal\": 4284976562,\n  \"AlternateBase:Normal\": 4281216558,\n  \"Dark:Normal\": 4280624421,\n  \"Window:Inactive\": 4282664004,\n  \"LinkVisited:Normal\": 4283570315,\n  \"Link:Normal\": 4278190318,\n  \"Base:Active\": 4280953386,\n  \"Mid:Inactive\": 4281150765,\n  \"Foreground:Disabled\": 4286611584,\n  \"Text:Normal\": 4291348680,\n  \"Link:Inactive\": 4278190318,\n  \"ButtonText:Normal\": 4291348680,\n  \"WindowText:Inactive\": 4291348680,\n  \"ToolTipBase:Normal\": 4294967260,\n  \"ToolTipText:Inactive\": 4278190080,\n  \"WindowText:Disabled\": 4286611584,\n  \"ToolTipText:Normal\": 4278190080,\n  \"Midlight:Active\": 4282071867,\n  \"ButtonText:Active\": 4291348680,\n  \"BrightText:Normal\": 4280624421,\n  \"Text:Active\": 4291348680,\n  \"Mid:Normal\": 4281150765,\n  \"WindowText:Active\": 4291348680,\n  \"Base:Normal\": 4280953386,\n  \"Background:Normal\": 4282664004,\n  \"Mid:Disabled\": 4281150765,\n  \"Background:Disabled\": 4282664004,\n  \"Link:Disabled\": 4278190318,\n  \"Window:Normal\": 4282664004,\n  \"Shadow:Active\": 4278190080,\n  \"Text:Inactive\": 4291348680,\n  \"Button:Normal\": 4284769380,\n  \"Light:Normal\": 4284572001,\n  \"Link:Active\": 4278190318,\n  \"Background:Active\": 4282664004,\n  \"HighlightedText:Disabled\": 4294967295,\n  \"Shadow:Disabled\": 4278190080,\n  \"ToolTipText:Disabled\": 4278190080,\n  \"Foreground:Normal\": 4291348680,\n  \"LinkVisited:Disabled\": 4283570315,\n  \"Shadow:Normal\": 4278190080,\n  \"Foreground:Inactive\": 4291348680\n}"
  },
  {
    "path": "src/pyvfx_boilerplate/resources/qpalette_maya2016.json",
    "content": "{\n  \"Foreground:Active\": 4290493371,\n  \"HighlightedText:Active\": 4294967295,\n  \"Mid:Active\": 4281150765,\n  \"WindowText:Normal\": 4290493371,\n  \"Window:Disabled\": 4282664004,\n  \"AlternateBase:Inactive\": 4281216558,\n  \"Midlight:Normal\": 4281808695,\n  \"HighlightedText:Inactive\": 4294967295,\n  \"Text:Disabled\": 4285098345,\n  \"Midlight:Disabled\": 4281808695,\n  \"Midlight:Inactive\": 4281808695,\n  \"Highlight:Disabled\": 4283590260,\n  \"Base:Disabled\": 4281019179,\n  \"Window:Active\": 4282664004,\n  \"Background:Inactive\": 4282664004,\n  \"AlternateBase:Disabled\": 4281216558,\n  \"Button:Inactive\": 4284308829,\n  \"AlternateBase:Active\": 4281216558,\n  \"LinkVisited:Active\": 4283570315,\n  \"ToolTipBase:Inactive\": 4294967260,\n  \"Dark:Inactive\": 4280624421,\n  \"LinkVisited:Inactive\": 4283570315,\n  \"Dark:Disabled\": 4280624421,\n  \"Light:Inactive\": 4284572001,\n  \"ButtonText:Inactive\": 4293848814,\n  \"Dark:Active\": 4280624421,\n  \"Light:Disabled\": 4284572001,\n  \"Button:Disabled\": 4283124555,\n  \"Shadow:Inactive\": 4278190080,\n  \"ToolTipBase:Disabled\": 4294967260,\n  \"BrightText:Inactive\": 4280624421,\n  \"ToolTipBase:Active\": 4294967260,\n  \"Highlight:Active\": 4283598246,\n  \"BrightText:Disabled\": 4294967295,\n  \"Highlight:Inactive\": 4283598246,\n  \"ToolTipText:Active\": 4278190080,\n  \"Light:Active\": 4284572001,\n  \"Button:Active\": 4284308829,\n  \"ButtonText:Disabled\": 4286611584,\n  \"HighlightedText:Normal\": 4294967295,\n  \"Base:Inactive\": 4281019179,\n  \"BrightText:Active\": 4280624421,\n  \"Highlight:Normal\": 4283598246,\n  \"AlternateBase:Normal\": 4281216558,\n  \"Dark:Normal\": 4280624421,\n  \"Window:Inactive\": 4282664004,\n  \"LinkVisited:Normal\": 4283570315,\n  \"Link:Normal\": 4278190318,\n  \"Base:Active\": 4281019179,\n  \"Mid:Inactive\": 4281150765,\n  \"Foreground:Disabled\": 4286611584,\n  \"Text:Normal\": 4291348680,\n  \"Link:Inactive\": 4278190318,\n  \"ButtonText:Normal\": 4293848814,\n  \"WindowText:Inactive\": 4290493371,\n  \"ToolTipBase:Normal\": 4294967260,\n  \"ToolTipText:Inactive\": 4278190080,\n  \"WindowText:Disabled\": 4286611584,\n  \"ToolTipText:Normal\": 4278190080,\n  \"Midlight:Active\": 4281808695,\n  \"ButtonText:Active\": 4293848814,\n  \"BrightText:Normal\": 4280624421,\n  \"Text:Active\": 4291348680,\n  \"Mid:Normal\": 4281150765,\n  \"WindowText:Active\": 4290493371,\n  \"Base:Normal\": 4281019179,\n  \"Background:Normal\": 4282664004,\n  \"Mid:Disabled\": 4281150765,\n  \"Background:Disabled\": 4282664004,\n  \"Link:Disabled\": 4278190318,\n  \"Window:Normal\": 4282664004,\n  \"Shadow:Active\": 4278190080,\n  \"Text:Inactive\": 4291348680,\n  \"Button:Normal\": 4284308829,\n  \"Light:Normal\": 4284572001,\n  \"Link:Active\": 4278190318,\n  \"Background:Active\": 4282664004,\n  \"HighlightedText:Disabled\": 4294967295,\n  \"Shadow:Disabled\": 4278190080,\n  \"ToolTipText:Disabled\": 4278190080,\n  \"Foreground:Normal\": 4290493371,\n  \"LinkVisited:Disabled\": 4283570315,\n  \"Shadow:Normal\": 4278190080,\n  \"Foreground:Inactive\": 4290493371\n}"
  },
  {
    "path": "src/pyvfx_boilerplate/utils/__init__.py",
    "content": ""
  },
  {
    "path": "src/pyvfx_boilerplate/utils/get_set_palette_data_qt4.py",
    "content": "\"\"\"Set and get QPalette data from Maya\r\n\r\n# Example: fetch palette data from Maya\r\ndata = getPaletteInfo()\r\nprint data\r\nwrite_json(data)\r\n\r\n# Example: read palette JSON file and set palette\r\ndata = read_json()\r\nprint data\r\nsetPaletteFromDict(data)\r\nsetStylePlastique()\r\nsetMayaTweaks()\r\n\"\"\"\r\n\r\nimport json\r\n\r\nfrom PySide import QtGui\r\n\r\nSTYLE = \"plastique\"\r\nGROUPS = [\"Disabled\", \"Active\", \"Inactive\", \"Normal\"]\r\nROLES = [\r\n    \"AlternateBase\",\r\n    \"Background\",\r\n    \"Base\",\r\n    \"Button\",\r\n    \"ButtonText\",\r\n    \"BrightText\",\r\n    \"Dark\",\r\n    \"Foreground\",\r\n    \"Highlight\",\r\n    \"HighlightedText\",\r\n    \"Light\",\r\n    \"Link\",\r\n    \"LinkVisited\",\r\n    \"Mid\",\r\n    \"Midlight\",\r\n    \"Shadow\",\r\n    \"ToolTipBase\",\r\n    \"ToolTipText\",\r\n    \"Text\",\r\n    \"Window\",\r\n    \"WindowText\",\r\n]\r\n\r\n\r\ndef getPaletteInfo():\r\n    palette = QtGui.QApplication.palette()\r\n\r\n    # ColorGroups\r\n    groups = []\r\n    for name in dir(QtGui.QPalette):\r\n        curr_pallet = getattr(QtGui.QPalette, name)\r\n        if isinstance(curr_pallet, QtGui.QPalette.ColorGroup):\r\n            if name != \"All\" and name != \"NColorGroups\" and name != \"Current\":\r\n                print(\"ColorGroup: {}\".format(name))\r\n                groups.append(name)\r\n    # ColorRoles\r\n    roles = []\r\n    for name in dir(QtGui.QPalette):\r\n        if isinstance(getattr(QtGui.QPalette, name), QtGui.QPalette.ColorRole):\r\n            if name != \"NColorRoles\" and name != \"NoRole\":\r\n                print(\"ColorGroup: {}\".format(name))\r\n                roles.append(name)\r\n\r\n    # build a dict with all the colors\r\n    result = {}\r\n    for role in ROLES:\r\n\r\n        for group in GROUPS:\r\n            qGrp = getattr(QtGui.QPalette, group)\r\n            qRl = getattr(QtGui.QPalette, role)\r\n            result[\"%s:%s\" % (role, group)] = palette.color(qGrp, qRl).rgba()\r\n    return result\r\n\r\n\r\ndef setPaletteFromDict(dct):\r\n    palette = QtGui.QPalette()\r\n    for role in ROLES:\r\n        for group in GROUPS:\r\n            color = QtGui.QColor(dct[\"%s:%s\" % (role, group)])\r\n            qGrp = getattr(QtGui.QPalette, group)\r\n            qRl = getattr(QtGui.QPalette, role)\r\n            palette.setColor(qGrp, qRl, color)\r\n    QtGui.QApplication.setPalette(palette)\r\n\r\n\r\ndef setStylePlastique():\r\n    QtGui.QApplication.setStyle(STYLE)\r\n\r\n\r\ndef setMayaTweaks():\r\n    base_palette = QtGui.QApplication.palette()\r\n\r\n    # Set custom colors\r\n    LIGHT_COLOR = QtGui.QColor(100, 100, 100)\r\n    MID_COLOR = QtGui.QColor(68, 68, 68)\r\n\r\n    # Create a new palette\r\n    tab_palette = QtGui.QPalette(base_palette)\r\n    tab_palette.setBrush(QtGui.QPalette.Window, QtGui.QBrush(LIGHT_COLOR))\r\n    tab_palette.setBrush(QtGui.QPalette.Button, QtGui.QBrush(MID_COLOR))\r\n\r\n    # Define the widgets that needs tweaking\r\n    widget_palettes = {}\r\n    widget_palettes[\"QTabBar\"] = tab_palette\r\n    widget_palettes[\"QTabWidget\"] = tab_palette\r\n\r\n    # Set the new tweaked palette\r\n    for name, palette in widget_palettes.items():\r\n        QtGui.QApplication.setPalette(palette, name)\r\n\r\n\r\ndef write_json(data):\r\n    with open(\"/Users/fredrik/Desktop/qpalette.json\", \"w\") as outfile:\r\n        json.dump(data, outfile)\r\n\r\n\r\ndef read_json():\r\n    # read\r\n    with open(\"/Users/fredrik/Desktop/qpalette.json\", \"r\") as handle:\r\n        data = json.load(handle)\r\n    return data\r\n"
  },
  {
    "path": "src/pyvfx_boilerplate/utils/get_set_palette_data_qt5.py",
    "content": "\"\"\"Set and get QPalette data from Maya\r\n\r\n# Example: fetch palette data from Maya\r\ndata = getPaletteInfo()\r\nprint data\r\nwrite_json(data)\r\n\r\n# Example: read palette JSON file and set palette\r\ndata = read_json()\r\nprint data\r\nsetPaletteFromDict(data)\r\nsetStylePlastique()\r\nsetMayaTweaks()\r\n\"\"\"\r\n\r\nimport json\r\n\r\nfrom PySide2 import QtGui\r\n\r\nSTYLE = \"plastique\"\r\nGROUPS = [\"Disabled\", \"Active\", \"Inactive\", \"Normal\"]\r\nROLES = [\r\n    \"AlternateBase\",\r\n    \"Background\",\r\n    \"Base\",\r\n    \"Button\",\r\n    \"ButtonText\",\r\n    \"BrightText\",\r\n    \"Dark\",\r\n    \"Foreground\",\r\n    \"Highlight\",\r\n    \"HighlightedText\",\r\n    \"Light\",\r\n    \"Link\",\r\n    \"LinkVisited\",\r\n    \"Mid\",\r\n    \"Midlight\",\r\n    \"Shadow\",\r\n    \"ToolTipBase\",\r\n    \"ToolTipText\",\r\n    \"Text\",\r\n    \"Window\",\r\n    \"WindowText\",\r\n]\r\n\r\n\r\ndef getPaletteInfo():\r\n    palette = QtGui.QGuiApplication.palette()\r\n\r\n    # ColorGroups\r\n    groups = []\r\n    for name in dir(QtGui.QPalette):\r\n        curr_pallet = getattr(QtGui.QPalette, name)\r\n        if isinstance(curr_pallet, QtGui.QPalette.ColorGroup):\r\n            if name != \"All\" and name != \"NColorGroups\" and name != \"Current\":\r\n                print(\"ColorGroup: {}\".format(name))\r\n                groups.append(name)\r\n    # ColorRoles\r\n    roles = []\r\n    for name in dir(QtGui.QPalette):\r\n        if isinstance(getattr(QtGui.QPalette, name), QtGui.QPalette.ColorRole):\r\n            if name != \"NColorRoles\" and name != \"NoRole\":\r\n                print(\"ColorGroup: {}\".format(name))\r\n                roles.append(name)\r\n\r\n    # build a dict with all the colors\r\n    result = {}\r\n    for role in ROLES:\r\n\r\n        for group in GROUPS:\r\n            qGrp = getattr(QtGui.QPalette, group)\r\n            qRl = getattr(QtGui.QPalette, role)\r\n            result[\"%s:%s\" % (role, group)] = palette.color(qGrp, qRl).rgba()\r\n    return result\r\n\r\n\r\ndef setPaletteFromDict(dct):\r\n    palette = QtGui.QPalette()\r\n    for role in ROLES:\r\n        for group in GROUPS:\r\n            color = QtGui.QColor(dct[\"%s:%s\" % (role, group)])\r\n            qGrp = getattr(QtGui.QPalette, group)\r\n            qRl = getattr(QtGui.QPalette, role)\r\n            palette.setColor(qGrp, qRl, color)\r\n    QtGui.QApplication.setPalette(palette)\r\n\r\n\r\ndef setStylePlastique():\r\n    QtGui.QApplication.setStyle(STYLE)\r\n\r\n\r\ndef setMayaTweaks():\r\n    base_palette = QtGui.QApplication.palette()\r\n\r\n    # Set custom colors\r\n    LIGHT_COLOR = QtGui.QColor(100, 100, 100)\r\n    MID_COLOR = QtGui.QColor(68, 68, 68)\r\n\r\n    # Create a new palette\r\n    tab_palette = QtGui.QPalette(base_palette)\r\n    tab_palette.setBrush(QtGui.QPalette.Window, QtGui.QBrush(LIGHT_COLOR))\r\n    tab_palette.setBrush(QtGui.QPalette.Button, QtGui.QBrush(MID_COLOR))\r\n\r\n    # Define the widgets that needs tweaking\r\n    widget_palettes = {}\r\n    widget_palettes[\"QTabBar\"] = tab_palette\r\n    widget_palettes[\"QTabWidget\"] = tab_palette\r\n\r\n    # Set the new tweaked palette\r\n    for name, palette in widget_palettes.items():\r\n        QtGui.QApplication.setPalette(palette, name)\r\n\r\n\r\ndef write_json(data):\r\n    with open(\"/Users/fredrik/Desktop/qpalette.json\", \"w\") as outfile:\r\n        json.dump(data, outfile)\r\n\r\n\r\ndef read_json():\r\n    # read\r\n    with open(\"/Users/fredrik/Desktop/qpalette.json\", \"r\") as handle:\r\n        data = json.load(handle)\r\n    return data\r\n"
  }
]