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