Integrating up through commit 90f050496

This commit is contained in:
alexpete
2021-04-07 14:03:29 -07:00
parent 8f2ed080a9
commit c2cbd430fe
2694 changed files with 285622 additions and 176874 deletions
@@ -10,14 +10,13 @@
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -- This line is 75 characters -------------------------------------------
# The __init__.py files help guide import statements without automatically
# importing all of the modules
# -------------------------------------------------------------------------
"""azpy.shared.ui.__init__"""
import os
from azpy import env_bool
from azpy.env_bool import env_bool
from azpy.constants import ENVAR_DCCSI_GDEBUG
from azpy.constants import ENVAR_DCCSI_DEV_MODE
@@ -0,0 +1,355 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -------------------------------------------------------------------------
from __future__ import unicode_literals
# from builtins import str
# built in's
import os
import sys
import uuid
import weakref
import logging as _logging
# 3rd Party
from unipath import Path
# azpy extensions
import azpy.config_utils
_config = azpy.config_utils.get_dccsi_config()
settings = _config.get_config_settings(setup_ly_pyside=True)
import PySide2.QtWidgets as QtWidgets
import PySide2.QtCore as QtCore
from shiboken2 import wrapInstance
# -------------------------------------------------------------------------
# global space debug flag
_G_DEBUG = settings.DCCSI_GDEBUG
# global space debug flag
_DCCSI_DEV_MODE = settings.DCCSI_DEV_MODE
# global maya state (if we are running in maya with gui)
# or another dcc tool with pyside2
# TODO implement that check
_G_PYSIDE2_DCC = None
_MODULE_PATH = Path(__file__)
_MODULENAME = 'azpy.shared.ui.azpy_base_widget'
_LOGGER = _logging.getLogger(_MODULENAME)
_LOGGER.debug('Something invoked :: {0}.'.format(_MODULENAME))
# -------------------------------------------------------------------------
class DccWidget(object):
"""This is an experimental Class to make a widget compatible with
a number of PySide2/Python compatible DCC Tools like Maya and Houdini"""
_LABEL_NAME = 'no name window' # Window display name
_instances = list()
# --constructor--------------------------------------------------------
def __init__(self, parent=None, dcc_gui=_G_PYSIDE2_DCC, *args, **kwargs):
# False or None, 'Maya', 'Houdini' ... or another pysdie2 dcc
self._dcc_gui = dcc_gui
self._name = '{0}_{1}'.format(self.__class__.__name__, uuid.uuid4())
self._parent = parent
self._parent = self._base_setup()
# Init all baseclasses (including QWidget) of the main class
try:
super().__init__(*args, **kwargs)
except Exception as Err:
print(Err)
self.__class__._instances.append(weakref.proxy(self))
if isinstance(self, QtWidgets.QWidget):
self.setParent(self._parent)
# camel case because this is a Qt|Pyside2 widget method
if self.objectName() == '':
# Set a unique object name string so Maya can easily look it up
self.setObjectName('{0}_{1}'.format(self._name))
# -- properties -------------------------------------------------------
@property
def dcc_gui(self):
return self._dcc_gui
@dcc_gui.setter
def dcc_gui(self, type):
self._dcc_gui = type
return self._dcc_gui
@dcc_gui.getter
def dcc_gui(self):
return self._dcc_gui
@property
def parent(self):
return self._parent
@parent.setter
def parent(self, type):
self._parent = type
return self._parent
@parent.getter
def parent(self):
return self._parent
# ---------------------------------------------------------------------
def _base_setup(self, *args, **kwargs):
'''TODO'''
# if there is not a parent, we want a mainwindow to parent to
if self.parent == None:
self.parent = self._make_standalone_mainwindow()
return self.parent
def _make_standalone_mainwindow(self):
'''Make a standalone mainwindow parent to existing Qapp
We parent so that this Qwidget will not be auto-destroyed or garbage
collected if the instance variable goes out of scope.
If a Qapp doesn't exist, start one.
'''
original_parent = self._parent
new_parent = None
if self.dcc_gui:
if self.dcc_gui == 'Maya':
# import the Maya ui class
import OpenMaya as omui
# Parent under the main Maya window
mainWindowPtr = omui.MQtUtil.mainWindow()
new_parent = wrapInstance(long(mainWindowPtr), QMainWindow)
elif self.dcc_gui == 'Houdini':
pass # not implemented
else:
from azpy.shared.ui.templates import TemplateMainWindow
new_parent = TemplateMainWindow()
return new_parent
def objectName(self):
# stand in for Qt call on mixed objects, thus camelCase
return None
def show(self):
# stand in for Qt call on mixed objects, thus camelCase
return None
def thing(self):
# Make this widget appear as a standalone window even though it is parented
if isinstance(self, QtWidgets.QDockWidget):
self.setWindowFlags(QtCore.Qt.Dialog | QtCore.Qt.FramelessWindowHint)
else:
try:
self.setWindowFlags(QtCore.Qt.Window)
except:
pass
# Delete the parent QDockWidget if applicable
if isinstance(original_parent, QtWidgets.QDockWidget):
original_parent.close()
# -------------------------------------------------------------------------
class BaseQwidgetAzpy(object):
"""Inheret from to handle common base functionality for Qt Widgets
Parents to a standalone Qapp and mainwindow if not explicitly provided
Place this before the Qt Widget Class in inheretance order"""
_LABEL_NAME = 'no name window' # Window display name
_instances = list()
_ORG_TAG = 'Amazon_Lumberyard'
_APP_TAG = 'DCCsi'
# --constructor--------------------------------------------------------
def __init__(self,
parent=None,
logger=None,
qapp=None,
window_title=_LABEL_NAME,
*args, **kwargs):
"""To DO"""
self._name_uuid = '{0}_{1}'.format(self.__class__.__name__, uuid.uuid4())
self._logger = logger
if not self._logger:
self._logger = _logging.getLogger(self._name_uuid)
self._parent = parent
self._qapp = qapp or QtWidgets.QApplication.instance()
if self._qapp == None:
self.logger.debug('No QApplication has been instantiated')
self._qapp = self._base_setup(window_title)
# Init all baseclasses (including QWidget) of the main class
try:
super(BaseQwidgetAzpy, self).__init__(*args, **kwargs)
except Exception as Err:
print(Err)
self.__class__._instances.append(weakref.proxy(self))
if isinstance(self, QtWidgets.QWidget):
self.setParent(self._parent)
# camel case because this is a Qt|Pyside2 widget method
if self.objectName() == '':
# Set a unique object name string so Maya can easily look it up
self.setObjectName(self._name)
# -- properties -------------------------------------------------------
@property
def parent(self):
return self._parent
@parent.setter
def parent(self, type):
self._parent = type
return self._parent
@parent.getter
def parent(self):
return self._parent
@property
def logger(self):
return self._logger
@logger.setter
def logger(self, logger):
self._logger = logger
return self._logger
@logger.getter
def logger(self):
return self._logger
@property
def qapp(self):
return self._qapp
@qapp.setter
def qapp(self, qapp):
self._qapp = qapp
return self._qapp
@qapp.getter
def qapp(self):
return self._qapp
# ----------------------------------------------------------------------
def objectName(self):
# stand in for Qt call on mixed objects, thus camelCase
return self._name_uuid
def show(self):
# stand in for Qt call on mixed objects, thus camelCase
return None
def _base_setup(self, *args, **kwargs):
'''TODO'''
# if there is not a parent, we want a mainwindow to parent to
if self.parent == None:
try:
self.parent = self._make_standalone_app(self.objectName())
except:
self.parent = self._make_standalone_app(self._name_uuid)
return self.parent
def _make_standalone_app(self, name):
useGUI = not '-no-gui' in sys.argv
self.qapp = QtWidgets.QApplication(sys.argv) if useGUI else QtWidgets.QCoreApplication(sys.argv)
self.qapp.setOrganizationName(self.__class__._ORG_TAG)
self.qapp.setApplicationName('{app}:{tool}'.format(app=self.__class__._APP_TAG,
tool=name))
return self.qapp
@QtCore.Slot()
def closeEvent(self, *args, **kwargs):
"""Event which is run when window closes"""
self.logger.debug("Method: {0}.{1}".format(self.__class__.__name__, 'closeEvent'))
self.logger.debug("Closing: {0}".format(self.objectName()))
self.__class__._instances.remove(self)
self.qapp.instance().quit
self.qapp.exit()
# ----------------------------------------------------------------------
# -------------------------------------------------------------------------
class TestWidget(BaseQwidgetAzpy, QtWidgets.QPushButton):
def __init__(self, parent=None, *args, **kwargs):
# Init all baseclasses (including QWidget) of the main class
try:
super().__init__(*args, **kwargs)
except Exception as Err:
print(Err)
try:
self.logger.debug('{0}'.format(self.parent))
except Exception as Err:
print(Err)
# self.setParent(parent)
self.setText('Push Me')
# -------------------------------------------------------------------------
if __name__ == '__main__':
"""Run this file as main"""
import sys
_TEST_APP_NAME = '{0}-{1}'.format(_MODULENAME, 'TEST')
_LOGGER = azpy.initialize_logger(_TEST_APP_NAME,
log_to_file=True,
default_log_level=_logging.DEBUG)
from azpy.constants import STR_CROSSBAR
_LOGGER.info(STR_CROSSBAR)
_LOGGER.info("{0} :: if __name__ == '__main__':".format(_MODULENAME))
_LOGGER.info(STR_CROSSBAR)
# test raw BaseWidget
_TEST_BASE_WIDGET = BaseQwidgetAzpy()
_LOGGER.info(_TEST_BASE_WIDGET.objectName())
_TEST_BASE_WIDGET.show() # this should do nothing,it is a dummy call
# this call is replaced with version the QWidget
_TEST_BASE_WIDGET.closeEvent() # mimic Qt close
_TEST_BASE_WIDGET = None
# NEED TO DELETE ^ Makes a Qapp
_TEST_WIDGET = TestWidget()
_LOGGER.info(_TEST_WIDGET.objectName())
_TEST_WIDGET.show()
del _LOGGER
sys.exit(_TEST_WIDGET.qapp.exec_())
# -------------------------------------------------------------------------
@@ -0,0 +1,89 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -------------------------------------------------------------------------
from __future__ import unicode_literals
# from builtins import str
# built in's
import os
# from io import StringIO # for handling unicode strings
# azpy
from azpy import initialize_logger
# 3rd Party
from unipath import Path
import PySide2.QtCore as QtCore
import PySide2.QtWidgets as QtWidgets
import PySide2.QtGui as QtGui
# -------------------------------------------------------------------------
# global space debug flag
_G_DEBUG = os.getenv('DCCSI_GDEBUG', False)
# global space debug flag
_DCCSI_DEV_MODE = os.getenv('DCCSI_DEV_MODE', False)
_MODULE_PATH = Path(__file__)
_ORG_TAG = 'Amazon_Lumberyard'
_APP_TAG = 'DCCsi'
_TOOL_TAG = 'azpy.shared.ui.custom_treemodel'
_TYPE_TAG = 'test'
_MODULENAME = __name__
if _MODULENAME is '__main__':
_MODULENAME = _TOOL_TAG
_UI_FILE = Path(_MODULE_PATH.parent, 'resources', 'example.ui')
# -------------------------------------------------------------------------
###########################################################################
## CustomTreeModel, Class
# -------------------------------------------------------------------------
class CustomFileTreeModel(QtCore.QAbstractItemModel):
"""
Creates a customized model subclassed from, QAbstractItemModel
Compatible with a TreeView
"""
# --constructor--------------------------------------------------------
def __init__(self, parent=None, *args, **kwargs):
'''
Constructor, INPUTS: Node, QObject
'''
super(CustomFileTreeModel, self).__init__(parent=parent, *args, **kwargs)
# can use these later (maybe?)
# easily extended later, TODO implement as property, add append
self._file_ext_list = ['.sbs', '.sbsar']
# we assume this is a file tree, we need a root path (lmbr project?)
self._root_filepath = root_filepath
# TODO: need to make sure we are getting path objects
# build the root node
self._root_node = self.buildRootNode('root', None, self._rootFilePath)
# master selection
self._masterSelection = masterSelection
# build the master selection node
self._masterNode = self.buildMasterNode('master', None, self._masterSelection, self._rootNode.path())
# want to store off a couple lists in the model, for retreival later
self._nodeList = None
self._depNodesList = None
@@ -0,0 +1,214 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -------------------------------------------------------------------------
"""help_menu.py: Setup a standard Help item in the menubar for PySide2 GUIs"""
# built in's
import os
import logging
# azpy
from azpy import initialize_logger
# import azpy.shared.ui.qt_settings as qt_settings
# 3rd Party
from unipath import Path
import PySide2.QtCore as QtCore
import PySide2.QtGui as QtGui
import PySide2.QtWidgets as QtWidgets
# -------------------------------------------------------------------------
# global space debug flag
_G_DEBUG = os.getenv('DCCSI_GDEBUG', False)
# global space developer mode flag
_DCCSI_DEV_MODE = os.getenv('DCCSI_DEV_MODE', False)
_MODULE_PATH = Path(__file__)
_ORG_TAG = 'Amazon_Lumberyard'
_APP_TAG = 'DCCsi'
_TOOL_TAG = 'azpy.shared.ui.help_menu'
_TYPE_TAG = 'test'
_MODULENAME = __name__
if _MODULENAME is '__main__':
_MODULENAME = _TOOL_TAG
_LOGGER = logging.getLogger(_MODULENAME)
_LOGGER.debug('Something invoked :: {0}.'.format({_MODULENAME}))
# TODO: implement this
# checks the run configuration to determine if we are running in maya
_G_MAYA = False
try:
from azpy.config.maya import _G_MAYA
if _G_MAYA:
import maya.cmds as mc
except:
pass
# -------------------------------------------------------------------------
class HelpMenu():
"""
Setup a standard Help item in the menubar for PySide2 GUIs
INPUTS:
main_window = the class instance of the QMainWindow
tool_label = the menu label for the tool's help item
tool_help_page = the http:// path to the specific bpTool help page
Here's an example
# self.help_menu = azpy.shared.ui.help_menu.setup(self, 'Help...', 'https://some.site.com/azpy')
"""
# ----------------------------------------------------------------------
def __init__(self, main_window, tool_label, tool_help_page):
"""Constructor"""
self.main_window = main_window
# store mainwindow menubar, we can attach the Help menu to this
self.menubar = self.main_window.menuBar()
self.tool_label = tool_label
self.tool_help_page = tool_help_page
self.help_menu = QtWidgets.QMenu(self.menubar)
self.help_menu.setObjectName("help_menu")
self.help_menu.setTitle("Help")
self.generic_tool_help_setup()
self.specific_tool_help_setup()
self.tool_bug_report_setup()
# ----------------------------------------------------------------------
def specific_tool_help_setup(self):
""""""
self.tool_action_help = QtWidgets.QAction(self.main_window)
self.tool_action_help.setObjectName("tool_action_help")
self.help_menu.addAction(self.tool_action_help)
self.menubar.addAction(self.help_menu.menuAction())
self.tool_action_help.setText(self.tool_label)
self.main_window.connect(self.tool_action_help, QtCore.SIGNAL("triggered()"), self.tool_help_display)
# ----------------------------------------------------------------------
def generic_tool_help_setup(self):
""""""
self.azpy_tool_action_help = QtWidgets.QAction(self.main_window)
self.azpy_tool_action_help.setObjectName("azpy_tool_action_help")
self.help_menu.addAction(self.azpy_tool_action_help)
self.menubar.addAction(self.help_menu.menuAction())
self.azpy_tool_action_help.setText("DCCsi help...")
self.main_window.connect(self.azpy_tool_action_help, QtCore.SIGNAL("triggered()"), self.azpy_tool_help_display)
# ----------------------------------------------------------------------
def tool_bug_report_setup(self):
""""""
self.tool_action_bug_report = QtWidgets.QAction(self.main_window)
self.tool_action_bug_report.setObjectName("tool_action_bug_report")
self.help_menu.addAction(self.tool_action_bug_report)
self.menubar.addAction(self.help_menu.menuAction())
self.tool_action_bug_report.setText("Report a Tool Bug...")
self.main_window.connect(self.tool_action_bug_report, QtCore.SIGNAL("triggered()"), self.bug_report_display)
# ----------------------------------------------------------------------
def tool_help_display(self):
""""""
if _G_MAYA:
mc.showHelp(self.tool_help_page, absolute=True)
else:
_LOGGER.debug('This command, {0}: currently only works when running in Maya.'.format('tool_help_display'))
pass
# ----------------------------------------------------------------------
def azpy_tool_help_display(self):
""""""
if _G_MAYA:
mc.showHelp('https://some.site.com/azpy/maya_tools/', absolute=True)
else:
_LOGGER.debug('This command, {0}: currently only works when running in Maya.'.format('azpy_tool_help_display'))
pass
# ----------------------------------------------------------------------
def bug_report_display(self):
""""""
if _G_MAYA:
mc.showHelp('https://some.site.com/azpy/report_bug', absolute=True)
else:
_LOGGER.debug('This command, {0}: currently only works when running in Maya.'.format('bug_report_display'))
pass
# -------------------------------------------------------------------------
class TestMainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setup_ui()
def setup_ui(self):
self.setWindowTitle('PySide2-HelpMenu-Test')
# Setup Help Menu
self.help_menu = HelpMenu(self, 'PySide2-Test Help...', 'http://dccSI.com/NewTool')
# main widget
self.main_widget = QtWidgets.QWidget(self)
self.setCentralWidget(self.main_widget)
# layout initialize
self.global_layout = QtWidgets.QVBoxLayout()
self.main_widget.setLayout(self.global_layout)
# Add Widgets
self.spinbox = QtWidgets.QSpinBox()
self.spinbox.setValue(30)
layout = QtWidgets.QFormLayout()
layout.addRow('Parameter', self.spinbox)
self.button = QtWidgets.QPushButton('Execute')
# global layout setting
self.global_layout.addLayout(layout)
self.global_layout.addWidget(self.button)
# ----------------------------------------------------------------------
def closeEvent(self, event):
"""Event which is run when window closes"""
_LOGGER.debug("Exiting: {0}".format(_TOOL_TAG))
# ----------------------------------------------------------------------
# -------------------------------------------------------------------------
if __name__ == '__main__':
"""Run this file as main"""
import sys
_LOGGER.debug("{0} :: if __name__ == '__main__':".format(_TOOL_TAG))
_LOGGER.debug("Starting App: {0} ...".format(_TOOL_TAG))
app = QtWidgets.QApplication(sys.argv)
mainWin = TestMainWindow()
mainWin.show()
del _LOGGER
sys.exit(app.exec_())
@@ -0,0 +1,173 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -------------------------------------------------------------------------
from __future__ import unicode_literals
# from builtins import str
# built in's
import sys
import os
import uuid
# azpy
from azpy import initialize_logger
from azpy.shared.ui.base_widget import BaseQwidgetAzpy
# 3rd Party
from unipath import Path
import PySide2.QtCore as QtCore
import PySide2.QtWidgets as QtWidgets
from PySide2.QtCore import QProcess, Signal, Slot, QTextCodec
from PySide2.QtGui import QTextCursor
from PySide2.QtWidgets import QPlainTextEdit
from PySide2.QtCore import QTimer
# -------------------------------------------------------------------------
# global space debug flag
_G_DEBUG = os.getenv('DCCSI_GDEBUG', False)
# global space debug flag
_DCCSI_DEV_MODE = os.getenv('DCCSI_DEV_MODE', False)
_MODULE_PATH = Path(__file__)
_ORG_TAG = 'Amazon_Lumberyard'
_APP_TAG = 'DCCsi'
_TOOL_TAG = 'azpy.shared.ui.pyside2_qtextedit_stdout'
_TYPE_TAG = 'test'
_MODULENAME = __name__
if _MODULENAME is '__main__':
_MODULENAME = _TOOL_TAG
if _G_DEBUG:
_LOGGER = initialize_logger(_MODULENAME, log_to_file=True)
_LOGGER.debug('Something invoked :: {0}.'.format({_MODULENAME}))
else:
_LOGGER = initialize_logger(_MODULENAME)
# -------------------------------------------------------------------------
class ProcessOutputReader(QProcess):
produce_output = Signal(str)
def __init__(self, parent=None):
super().__init__(parent=parent)
# merge stderr channel into stdout channel
self.setProcessChannelMode(QProcess.MergedChannels)
# prepare decoding process' output to Unicode
self._codec = QTextCodec.codecForLocale()
self._decoder_stdout = self._codec.makeDecoder()
# only necessary when stderr channel isn't merged into stdout:
# self._decoder_stderr = codec.makeDecoder()
self.readyReadStandardOutput.connect(self._ready_read_standard_output)
# only necessary when stderr channel isn't merged into stdout:
# self.readyReadStandardError.connect(self._ready_read_standard_error)
@Slot()
def _ready_read_standard_output(self):
raw_bytes = self.readAllStandardOutput()
text = self._decoder_stdout.toUnicode(raw_bytes)
self.produce_output.emit(text)
# only necessary when stderr channel isn't merged into stdout:
# @Slot()
# def _ready_read_standard_error(self):
# raw_bytes = self.readAllStandardError()
# text = self._decoder_stderr.toUnicode(raw_bytes)
# self.produce_output.emit(text)
# --------------------------------------------------------------------------
class MyConsole(BaseQwidgetAzpy, QPlainTextEdit):
def __init__(self, parent=None):
super().__init__(parent=parent)
# Set a unique object name string so Maya can easily look it up
self.setObjectName('{0}_{1}'.format(self.__class__.__name__,
uuid.uuid4()))
self.setReadOnly(True)
self.setMaximumBlockCount(10000) # limit console to 10000 lines
self._cursor_output = self.textCursor()
@Slot(str)
def append_output(self, text):
self._cursor_output.insertText(text)
self.scroll_to_last_line()
def scroll_to_last_line(self):
cursor = self.textCursor()
cursor.movePosition(QTextCursor.End)
cursor.movePosition(QTextCursor.Up if cursor.atBlockStart() else
QTextCursor.StartOfLine)
self.setTextCursor(cursor)
def output_text(self, text):
self._cursor_output.insertText(text)
self.scroll_to_last_line()
# --------------------------------------------------------------------------
if __name__ == '__main__':
"""Run this file as main"""
import sys
_ORG_TAG = 'Amazon_Lumberyard'
_APP_TAG = 'DCCsi'
_TOOL_TAG = 'azpy.shared.ui.pyside2_qtextedit_stdout'
_TYPE_TAG = 'test'
if _G_DEBUG:
_LOGGER = initialize_logger('{0}-TEST'.format(_TOOL_TAG), log_to_file=True)
_LOGGER.debug('Something invoked :: {0}.'.format({_MODULENAME}))
_LOGGER.debug("{0} :: if __name__ == '__main__':".format(_TOOL_TAG))
_LOGGER.debug("Starting App:{0} TEST ...".format(_TOOL_TAG))
# # create the application instance
# _APP = QtWidgets.QApplication(sys.argv)
# _APP.setOrganizationName(_ORG_TAG)
# _APP.setApplicationName('{app}:{tool}'.format(app=_APP_TAG, tool=_TOOL_TAG))
# create a console and connect the process output reader to it
_CONSOLE = MyConsole()
# create a process output reader
_READER = ProcessOutputReader(parent=_CONSOLE)
_READER.produce_output.connect(_CONSOLE.append_output)
# start something and log (including to console)
# this starts a test app
_TEST_PY_FILE = Path(_MODULE_PATH.parent, 'pyside2_ui_utils.py')
_READER.start('python', ['-u', _TEST_PY_FILE]) # start the process
# after that starts, this will show the console
# LY_QSS = Path(_MODULE_PATH.parent, 'resources', 'stylesheets', 'LYstyle.qss')
_DARK_STYLE = Path(_MODULE_PATH.parent, 'resources', 'qdarkstyle', 'style.qss')
_CONSOLE.qapp.setStyleSheet(_DARK_STYLE.read_file())
_CONSOLE.show() # make the console visible
_LOGGER.debug(_CONSOLE.objectName())
_TIMER = QTimer()
_TIMER.timeout.connect(lambda: None)
_TIMER.start(100)
del _LOGGER
sys.exit(_CONSOLE.qapp.exec_())
@@ -0,0 +1,189 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -------------------------------------------------------------------------
#
from __future__ import unicode_literals
# from builtins import str
# built in's
import os
import site
import uuid
import logging as _logging
import xml.etree.ElementTree as xml # Qt .ui files are xml
from io import StringIO # for handling unicode strings
# azpy extensions
import azpy.config_utils
_config = azpy.config_utils.get_dccsi_config()
# ^ this is effectively an import and retreive of <dccsi>\config.py
# and init's access to Qt/Pyside2
# init lumberyard Qy/PySide2 access
# now default settings are extended with PySide2
# this is an alternative to "from dynaconf import settings" with Qt
settings = _config.get_config_settings(setup_ly_pyside=True)
# 3rd Party (we may or do provide)
from unipath import Path
# now we can import lumberyards PySide2
import PySide2.QtCore as QtCore
import PySide2.QtWidgets as QtWidgets
import PySide2.QtGui as QtGui
from PySide2.QtWidgets import QApplication, QSizePolicy
import PySide2.QtUiTools as QtUiTools
# special case for import pyside2uic
site.addsitedir(settings.DCCSI_PYSIDE2_TOOLS)
import pyside2uic
# azpy
import azpy.shared.ui.qt_settings as qt_settings
import azpy.shared.ui.help_menu as help_menu
# -------------------------------------------------------------------------
# global space debug flag
_G_DEBUG = settings.DCCSI_GDEBUG
# global space debug flag
_DCCSI_DEV_MODE = settings.DCCSI_DEV_MODE
_MODULE_PATH = Path(__file__)
_ORG_TAG = 'Amazon_Lumberyard'
_APP_TAG = 'DCCsi'
_TOOL_TAG = 'azpy.shared.ui.pyside2_ui_utils'
_TYPE_TAG = 'test'
_MODULENAME = _TOOL_TAG
_LOGGER = _logging.getLogger(_MODULENAME)
_LOGGER.debug('Something invoked :: {0}.'.format(_MODULENAME))
_UI_FILE = Path(_MODULE_PATH.parent, 'resources', 'example.ui')
# -------------------------------------------------------------------------
class UiLoader(QtUiTools.QUiLoader):
def __init__(self, base_instance):
super(UiLoader, self).__init__(base_instance)
self._base_instance = base_instance
def createWidget(self, classname, parent=None, name=""):
widget = super(UiLoader, self).createWidget(
classname, parent, name)
if parent is None:
return self._base_instance
else:
setattr(self._base_instance, name, widget)
return widget
# -------------------------------------------------------------------------
class UiWidget(QtWidgets.QWidget):
def __init__(self, ui_file=_UI_FILE, parent=None):
super().__init__(parent)
loader = UiLoader(parent)
file = QFile(ui_file)
file.open(QFile.ReadOnly)
loader.load(file, self)
file.close()
# -------------------------------------------------------------------------
def from_ui_generate_form_and_base_class(filename, return_output=False):
"""Parse a Qt Designer .ui file and return Pyside2 Form and Base Class
Usage:
import azpy.shared.ui as azpyui
form_class, base_class = azpyui.from_ui_generate_form_and_class(r'C:\my\filepath\tool.ui')
"""
ui_file = Path(filename)
output = ''
parsed_xml = None
try:
ui_file.exists()
except FileNotFoundError as error:
output += 'File does not exist: {0}/r'.format(error)
if _G_DEBUG:
print(error)
if return_output:
return False, output
else:
return False
try:
ui_file.ext == 'ui'
except IOError as error:
output += 'Not a Qt Designer .ui file: {0}/r'.format(error)
if return_output:
return False, output
else:
return False
parsed_xml = xml.parse(ui_file)
form_class = parsed_xml.find('class').text
widget_class = parsed_xml.find('widget').get('class')
with open(ui_file, 'r') as ui_file:
stream = StringIO() # create a file io stream
frame = {}
_uic_compiler_path = Path(settings.DCCSI_PYSIDE2_TOOLS)
site.addsitedir(_uic_compiler_path)
import pyside2uic
# compile the .ui file as a .pyc represented in steam
pyside2uic.compileUi(ui_file, stream, indent=4)
# compile the .pyc bytecode from stream
pyc = compile(stream.getvalue(), '', 'exec')
# execute the .pyc bytecode
exec (pyc, frame)
# Retreive the form_class and base_class based on type in designer .ui (xml)
form_class = frame['Ui_{0}'.format(form_class)]
base_class = eval('QtWidgets.{0}'.format(widget_class))
ui_file.close()
if return_output:
return form_class, base_class, output
else:
return form_class, base_class
# -------------------------------------------------------------------------
if __name__ == '__main__':
"""Run this file as main"""
import sys
_LOGGER = azpy.initialize_logger('{0}-TEST'.format(_TOOL_TAG), log_to_file=True)
_LOGGER.debug('Something invoked :: {0}.'.format({_MODULENAME}))
_LOGGER.info("{0} :: if __name__ == '__main__':".format(_TOOL_TAG))
_LOGGER.info("Starting App:{0} TEST ...".format(_TOOL_TAG))
_FORM_CLASS, _BASE_CLASS = from_ui_generate_form_and_base_class(_UI_FILE)
_LOGGER.info(_FORM_CLASS)
_LOGGER.info(_BASE_CLASS)
from azpy.shared.ui.templates import TemplateMainWindow
_MAIN_WINDOW = TemplateMainWindow(logger=_LOGGER)
_MAIN_WINDOW.show()
del _LOGGER
sys.exit(_MAIN_WINDOW.qapp.exec_())
# -------------------------------------------------------------------------
@@ -0,0 +1,84 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -------------------------------------------------------------------------
"""qt_settings.py: Manages a QSettings for a tool"""
# built in's
import os
import logging as _logging
# 3rd Party (we may provide)
from unipath import Path
from dynaconf import settings
# azpy extensions
import azpy.config_utils
_config = azpy.config_utils.get_dccsi_config()
# ^ this is effectively an import and retreive of <dccsi>\config.py
# init lumberyard Qy/PySide2 access
_config.init_ly_pyside(settings.LY_DEV)
# now we can import lumberyards PySide2
import PySide2.QtCore as QtCore
import PySide2.QtWidgets as QtWidgets
# -------------------------------------------------------------------------
# global space debug flag
_G_DEBUG = settings.DCCSI_GDEBUG
# global space debug flag
_DCCSI_DEV_MODE = settings.DCCSI_DEV_MODE
_MODULE_PATH = Path(__file__)
_ORG_TAG = 'Amazon_Lumberyard'
_APP_TAG = 'DCCsi'
_TOOL_TAG = 'azpy.shared.ui.qt_settings'
_TYPE_TAG = 'test'
_MODULENAME = _TOOL_TAG
_LOGGER = _logging.getLogger(_MODULENAME)
_LOGGER.debug('Something invoked :: {0}.'.format(_MODULENAME))
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
def createSettings(org='Amazon_Lumberyard', app='DCCsi',
tool='azpy', type='default'):
"""Sets up a settings .ini
Returns a QSettings instance"""
settings_folder = '{org}//{app}'.format(org=org, app=app)
settings_name = '{tool}-{type}'.format(tool=tool, type=type)
settings = QtCore.QSettings(QtCore.QSettings.IniFormat,
QtCore.QSettings.UserScope,
settings_folder, settings_name)
return settings
# -------------------------------------------------------------------------
if __name__ == '__main__':
"""Run this file as main"""
import sys
app = QtWidgets.QApplication(sys.argv)
app.setOrganizationName(_ORG_TAG)
app.setApplicationName('{app}:{tool}'.format(app=_APP_TAG, tool=_TOOL_TAG))
test_esttings = createSettings(_ORG_TAG, _APP_TAG, _TOOL_TAG, _TYPE_TAG)
_LOGGER.info(test_esttings)
_LOGGER.info(test_esttings.fileName())
@@ -0,0 +1,680 @@
# coding:utf-8
#!/usr/bin/python
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# -------------------------------------------------------------------------
from __future__ import unicode_literals
# from builtins import str
# built in's
import os
import sys
import logging as _logging
import uuid
import xml.etree.ElementTree as xml # Qt .ui files are xml
from io import StringIO # for handling unicode strings
# 3rd Party (we may or do provide)
from unipath import Path
# azpy extensions
import azpy.config_utils
_config = azpy.config_utils.get_dccsi_config()
# ^ this is effectively an import and retreive of <dccsi>\config.py
# and init's access to Qt/Pyside2
# init lumberyard Qy/PySide2 access
# now default settings are extended with PySide2
# this is an alternative to "from dynaconf import settings" with Qt
settings = _config.get_config_settings(setup_ly_pyside=True)
# now we can import lumberyards PySide2
import azpy.shared.ui.qt_settings as qt_settings
import azpy.shared.ui.help_menu as help_menu
import azpy.shared.ui.pyside2_ui_utils as ui_utils
import pyside2uic
import PySide2.QtCore as QtCore
import PySide2.QtWidgets as QtWidgets
import PySide2.QtGui as QtGui
import PySide2.QtUiTools as QtUiTools
# -------------------------------------------------------------------------
# global space debug flag
_G_DEBUG = settings.DCCSI_GDEBUG
# global space debug flag
_DCCSI_DEV_MODE = settings.DCCSI_DEV_MODE
_MODULE_PATH = Path(__file__)
_MODULENAME = 'azpy.shared.ui.teamplates'
_LOGGER = _logging.getLogger(_MODULENAME)
_LOGGER.debug('Something invoked :: {0}.'.format(_MODULENAME))
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# example .ui used as default (for tests, etc.)
_UI_FILE = Path(_MODULE_PATH.parent, 'resources', 'example.ui')
# Hmmm.... should be a better way to handle this?
_FORM_CLASS, _BASE_CLASS = ui_utils.from_ui_generate_form_and_base_class(_UI_FILE)
# looks like either we aren't compiling it or it's not provided in the current
# version of Qt we use (check mack Qt5.15)
# https://doc-snapshots.qt.io/qtforpython-5.15/PySide2/QtUiTools/ls.loadUiType.html)
#_FORM_CLASS, _BASE_CLASS = QtUiTools.loadUiType(_UI_FILE)
# print(QtUiTools.QUiLoader) <-- this one works differently but maybe that pattern is better?
# default dark styling for standalone apps
_DARK_STYLE = Path(_MODULE_PATH.parent, 'resources', 'qdarkstyle', 'style.qss')
# ^ lumberyard style doesn't work for all widgets, so this can be direcly applied
# to sidgets that look funny, they won't be a perfect match but also won't look odd
# To Do: make optional and/or force only when standalone
# adopt the Qt app style by default (use lumberyards style when it's the parent)
# include a standlaone lumberyard-like styling also
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# https://doc.qt.io/qt-5/designer-using-a-ui-file-python.html
# pattern #1
# pyside2-uic.exe form.ui > form.py
# results might be something like this:
#from ui_form import Ui_Form
# class UicWidget(QtWidgets.QWidget):
#def __init__(self, parent=None):
#super(Window, self).__init__(parent)
#self.m_ui = Ui_Form()
#self.m_ui.setupUi(self)
# pattern #2
# that could also be represented like?
# class SomeWidget(Ui_Form, QtWidgets.QWidget):
#def __init__(self, parent=None):
#super(Window, self).__init__(parent)
# self.setupUi(self)
# pattern 3, use QUiLoader
# you need to know the main widget class (QtWidgets.QWidget), load .ui form within class
#from PySide2.QtUiTools import QUiLoader
#from PySide2 import QtWidgets
#from PySide2.QtCore import QFile
#class MyForm(QtWidgets.QWidget):
#def __init__(self, parent=None):
#QtWidgets.QWidget.__init__(self, parent)
## read/load my .ui file
#file = QFile("form.ui")
#file.open(QFile.ReadOnly)
#self.loader = QUiLoader()
#self.my_widget = self.loader.load(file, self)
#file.close()
## setup my own layout
#layout = QtWidgets.QVBoxLayout()
#layout.addWidget(self.my_widget)
#self.setLayout(layout)
#if __name__ == '__main__':
#app = QtWidgets.QApplication(sys.argv)
#myapp = MyForm()
#myapp.show()
#sys.exit(app.exec_())
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# pattern 4 (I like this)
#_UI_FILE = Path(_MODULE_PATH.parent, 'resources', 'example.ui')
#_FORM_CLASS, _BASE_CLASS = ui_utils.from_ui_generate_form_and_base_class(_UI_FILE)
# here is basically what that returns ...
#parsed_xml = xml.parse(ui_file)
# form_class = parsed_xml.find('class').text # --> <class 'Ui_Form'>
# widget_class = parsed_xml.find('widget').get('class') # --> <class 'PySide2.QtWidgets.QWidget'>
#class MyToolWidget(TemplateToolWidget):
#def __init__(self, parent, *args, **kwargs):
#super().__init__(parent, *args, **kwargs)
#my_tool = MyToolWidget()
class TemplateToolWidget(_FORM_CLASS, _BASE_CLASS):
def __init__(self, parent, logger=None, *args, **kwargs):
'''A custom tool window with a demo set of template ui functionality'''
super().__init__(parent, *args, **kwargs)
self._logger = logger
if not self._logger:
try:
self._logger = self.parent().logger
except:
self._logger = azpy.initialize_logger(self.objectName())
self.logger.debug("Method: {0}.{1}".format(__class__, '__init__'))
# lets hope the parent is a mainwindow?
self.mainwindow = parent
self._project_directory = Path('C:\Lumberyard', 'Dev', 'Gems',
'DccScriptingInterface', 'MockProject')
# uic adds a function to our class called setupUi,
# calling this creates all the widgets from the .ui file
self.setupUi(self)
# this one is local to this class
self.setup_ui()
# Connect the interface controls
self.connect_interface()
# ----------------------------------------------------------------------
# -- properties --------------------------------------------------------
@property
def logger(self):
return self._logger
@logger.setter
def logger(self, logger):
self._logger = logger
return self._logger
@logger.getter
def logger(self):
return self._logger
# ----------------------------------------------------------------------
def setup_ui(self):
"""TODO: Doc String"""
# override this method to inject your own ui widgets amd layout
self.logger.debug("Method: {0}.{1}".format(__class__, 'setup_ui'))
self.helpMenu = help_menu.HelpMenu(self.mainwindow, 'TemplateToolTool Help...', 'http://dccSI.com/NewTool')
_DARK_STYLE = Path(_MODULE_PATH.parent, 'resources', 'qdarkstyle', 'style.qss')
try:
self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
except Exception as e:
self.logger.warning('warning! : {}'.format(e))
# override some of widgets to a better dark style
self.WatchdogList_treeView.setStyleSheet(_DARK_STYLE.read_file())
self.WatchdogList_treeView.setMinimumHeight(250)
self.output_console_textEdit.setStyleSheet(_DARK_STYLE.read_file())
self.output_console_textEdit.setMinimumHeight(250)
pass
# ----------------------------------------------------------------------
def set_defaults(self):
"""TODO: Doc String"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'set_defaults'))
pass
# ----------------------------------------------------------------------
def connect_interface(self):
"""TODO: Doc String"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'connect_interface'))
# Connect widgets to methods
# QtCore.QObject.connect(self.renameButton, QtCore.SIGNAL("clicked()"), self.NewCommand)
pass
# ----------------------------------------------------------------------
def new_command(self):
"""TODO: Doc String"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'new_command'))
pass
# ----------------------------------------------------------------------
# --------------------------------------------------------------------------
# --------------------------------------------------------------------------
class TemplateMainWindow(QtWidgets.QMainWindow):
"""TODO"""
_ORG_TAG = 'Amazon_Lumberyard'
_APP_TAG = 'DCCsi'
def __init__(self,
parent=None,
logger=None,
app=None,
custom_tool_widget=None,
window_title='TemplateToolWidget',
app_icon="icon.png",
*args, **kwargs):
"""TODO"""
# secret demo
demo = kwargs.pop('demo', False)
self._logger = logger
self._qapp = None
self._name_uuid = '{0}_{1}'.format(self.__class__.__name__, uuid.uuid4())
if not self._logger:
self._logger = azpy.initialize_logger(self._name_uuid)
# self._logger = initialize_logger()
self._qapp = app or QtWidgets.QApplication.instance()
if self._qapp is not None:
pass
else:
# self.logger.debug('No QApplication has been instantiated')
self._qapp = self._make_standalone_app(window_title)
super(TemplateMainWindow, self).__init__(parent=parent, *args, **kwargs)
# camel case because this is a Qt|Pyside2 widget method
if self.objectName() == '':
# Set a unique object name string so Maya can easily look it up
self.setObjectName(self._name_uuid)
self.window_title = window_title
if self.window_title == '':
self.window_title = self.objectName()
self.setWindowTitle(self.window_title)
self._style_sheet = None
if not self._style_sheet:
self._style_sheet = Path(_MODULE_PATH.parent, 'resources',
'stylesheets', 'LYstyle.qss')
self.setStyleSheet(self._style_sheet.read_file())
self.app_icon = app_icon
self._custom_widget = custom_tool_widget
if self._custom_widget:
self._custom_widget.parent(self)
self.setup_ui()
if demo:
custom_tool_widget = TemplateToolWidget(self)
self.add_custom_widget(custom_tool_widget)
# Setup the settings .ini
_TYPE_TAG = 'TEMPLATE'
self.settings = qt_settings.createSettings(TemplateMainWindow._ORG_TAG,
TemplateMainWindow._APP_TAG,
self.window_title, _TYPE_TAG)
# Read the saved settings
self.read_settings()
# ---------------------------------------------------------------------
def _make_standalone_app(self, name):
useGUI = not '-no-gui' in sys.argv
self.qapp = QtWidgets.QApplication(sys.argv) if useGUI else QtWidgets.QCoreApplication(sys.argv)
self.qapp.setOrganizationName(TemplateMainWindow._ORG_TAG)
self.qapp.setApplicationName('{app}:{tool}'.format(app=TemplateMainWindow._APP_TAG,
tool=name))
return self.qapp
# ----------------------------------------------------------------------
# -- properties --------------------------------------------------------
@property
def logger(self):
return self._logger
@logger.setter
def logger(self, logger):
self._logger = logger
return self._logger
@logger.getter
def logger(self):
return self._logger
@property
def custom_widget(self):
return self._lcustom_widget
@custom_widget.setter
def custom_widget(self, custom_widget):
self._custom_widget = custom_widget
return self._custom_widget
@custom_widget.getter
def custom_widget(self):
return self._custom_widget
@property
def qapp(self):
return self._qapp
@qapp.setter
def qapp(self, qapp):
self._qapp = qapp
return self._qapp
@qapp.getter
def qapp(self):
return self._qapp
@property
def app_icon(self):
return self._app_icon
@app_icon.setter
def app_icon(self, icon):
self._app_icon = QtGui.QIcon(icon)
self.setWindowIcon(self._app_icon)
return self._app_icon
@app_icon.getter
def app_icon(self):
return self._app_icon
def setIcon(self, icon):
self.app_icon = icon
# ----------------------------------------------------------------------
def setup_ui(self, *args, **kwargs):
# self.toolbar = QtWidgets.QToolBar()
# self.addToolBar(self.toolbar)
self.logger.debug("Method: {0}.{1}".format(__class__, 'setup_ui'))
self.setIcon = self.app_icon
# Exit QAction on hotkey
exit_tag = "Exit"
exit_action = QtWidgets.QAction(exit_tag, self)
exit_action.setShortcut("Ctrl+Q")
exit_action.triggered.connect(self.close)
# basic menubar File > Exit event
self.menu_bar = self.menuBar() # type: QMenuBar
file_menu = self.menu_bar.addMenu("File") # type: QMenu
file_menu.addAction(exit_tag, self.close)
# main widget
self.central_widget = QtWidgets.QWidget(self)
self.setCentralWidget(self.central_widget)
# layout initialize
self.global_layout = QtWidgets.QVBoxLayout(self.central_widget)
self.global_layout.setContentsMargins(8, 8, 8, 8)
self.central_widget.setLayout(self.global_layout)
self.createStatusBar()
# TODO: create a progress bar
# https://codeloop.org/how-to-create-progressbar-in-pyside2/amp/
# ----------------------------------------------------------------------
def add_custom_widget(self, custom_tool_widget=None):
# Add our TemplateToolWidget
if custom_tool_widget:
self.custom_widget = custom_tool_widget
self.custom_widget.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
layout = QtWidgets.QFormLayout()
self.global_layout.addLayout(layout)
self.global_layout.addWidget(self.custom_widget)
# else: # demo test tool
# self.custom_widget = TemplateToolWidget(self)
# ----------------------------------------------------------------------
def createStatusBar(self):
self.logger.debug("Method: {0}.{1}".format(__class__, 'createStatusBar'))
self.myStatus = QtWidgets.QStatusBar()
self.myStatus.showMessage("{0}: Ready".format(self.window_title), 3000)
self.setStatusBar(self.myStatus)
# ----------------------------------------------------------------------
@QtCore.Slot()
def closeEvent(self, event=None, *args, **kwargs):
"""Event which is run when window closes"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'closeEvent'))
close = QtWidgets.QMessageBox()
result = close.question(self,
"Confirm Exit...",
"Are you sure you want to exit ?",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
if result == QtWidgets.QMessageBox.Yes:
if event:
event.accept()
self.logger.debug("Closing: {0}".format(self.objectName()))
self.write_settings()
self.qapp.instance().quit
self.qapp.exit()
else:
if event:
event.ignore()
# ----------------------------------------------------------------------
def write_settings(self):
"""Writes out the windows settings"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'write_settings'))
# main window
# saves window size and position
self.settings.setValue("geometry", self.saveGeometry())
# saves the state of window's toolbars and dockWidgets
self.settings.setValue("windowState", self.saveState())
# widgets, save a setting to persist
# self.settings.setValue("textFilePath", self.textFileLineEdit.text())
# ----------------------------------------------------------------------
def read_settings(self):
"""Reads in the windows settings"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'read_settings'))
# main window
self.restoreGeometry(self.settings.value("geometry")) # restores window size and position
self.restoreState(self.settings.value("windowState")) # restores the state of window's toolbars and dockWidgets
# widgets, restore something from settings
# if self.settings.value("textFilePath"):
# textFile = self.qt_settings.value("textFilePath",).toString()
# self.textFileLineEdit.setText(textFile)
# ----------------------------------------------------------------------
# --------------------------------------------------------------------------
# --------------------------------------------------------------------------
class TestToolWidget(TemplateToolWidget):
def __init__(self, parent, *args, **kwargs):
'''A custom window with a demo set of ui widgets'''
super(TestToolWidget, self).__init__(parent=parent, *args, **kwargs)
self.logger.debug("Method: {0}.{1}".format(__class__, '__init__'))
# this one is local to this class
self.extend_ui()
self._test_property = 'Property Not set'
self.logger.debug("self._test_property: {0}".format(self._test_property))
self.class_tests()
# ----------------------------------------------------------------------
# -- properties --------------------------------------------------------
@property
def test_property(self):
return self._test_property
@test_property.setter
def test_property(self, test_property):
self._test_property = test_property
return self._test_property
@test_property.getter
def test_property(self):
return self._test_property
# ----------------------------------------------------------------------
def class_tests(self):
"""TODO: Doc String"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'class_tests'))
self.test_property = 'TEST PROPERTY'
self.logger.debug("self._test_property: {0}".format(self.test_property))
return
# ----------------------------------------------------------------------
def setup_ui(self):
"""TODO: Doc String"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'setup_ui'))
return
def extend_ui(self):
"""TODO: Doc String"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'extend_ui'))
# this would be local to this class, runs outside _init__
#
# self.setup_ui()
# Connect the interface controls
# self.connect_interface()
self._watchdog_list = QtGui.QStandardItemModel(parent=self)
self._project_directory = Path('C:\Lumberyard', 'Dev', 'Gems',
'DccScriptingInterface', 'MockProject')
# we want 2 columns
self._watchdog_list.setColumnCount(2)
# set up a temp watch dog folder watch list (as a model)
self._watchdog_list.setHorizontalHeaderLabels(['Path', 'State'])
_DARK_STYLE = Path(_MODULE_PATH.parent, 'resources', 'qdarkstyle', 'style.qss')
# override some of widgets to a better dark style
self.WatchdogList_treeView.setStyleSheet(_DARK_STYLE.read_file())
self.WatchdogList_treeView.setMinimumHeight(250)
self.WatchdogList_treeView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.WatchdogList_treeView.setModel(self._watchdog_list)
self.WatchdogList_treeView.setUniformRowHeights(True)
# populate treeView data
parent_item = self._watchdog_list.invisibleRootItem()
first_row = QtGui.QStandardItem(self._project_directory)
self._watchdog_list.appendRow(first_row)
# span container columns
self.WatchdogList_treeView.setFirstColumnSpanned(0, self.WatchdogList_treeView.rootIndex(), True)
TemplateMainWindow = QtGui.QStandardItem('\\Assets\\some\\path')
self._watchdog_list.appendRow(TemplateMainWindow)
first_row_state = QtGui.QStandardItem('{0}'.format('Active'))
# TemplateMainWindow.appendRow(first_row_state)
second_row = QtGui.QStandardItem('\\Assets\\another\\path')
self._watchdog_list.appendRow(second_row)
second_row_state = QtGui.QStandardItem('{0}'.format('Active'))
# second_row.appendRow(second_row_state)
first_row.appendRow([TemplateMainWindow, second_row])
# span container columns
self.WatchdogList_treeView.setFirstColumnSpanned(0, self.WatchdogList_treeView.rootIndex(), True)
self.output_console_textEdit.setStyleSheet(_DARK_STYLE.read_file())
self.output_console_textEdit.setMinimumHeight(250)
# TODO: create a progress bar
# https://codeloop.org/how-to-create-progressbar-in-pyside2/amp/
pass
# ----------------------------------------------------------------------
def set_defaults(self):
"""TODO: Doc String"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'extend_ui'))
pass
# ----------------------------------------------------------------------
def connect_interface(self):
"""TODO: Doc String"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'connect_interface'))
# Connect widgets to methods
# QtCore.QObject.connect(self.renameButton, QtCore.SIGNAL("clicked()"), self.NewCommand)
pass
# ----------------------------------------------------------------------
def new_command(self):
"""TODO: Doc String"""
self.logger.debug("Method: {0}.{1}".format(__class__, 'new_command'))
pass
# ----------------------------------------------------------------------
# --------------------------------------------------------------------------
# --------------------------------------------------------------------------
if __name__ == '__main__':
"""Run this file as main"""
import sys
_TEST_APP_NAME = '{0}-{1}'.format(_MODULENAME, 'TEST')
_LOGGER = azpy.initialize_logger(_TEST_APP_NAME,
log_to_file=True,
default_log_level=_logging.DEBUG)
from azpy.constants import STR_CROSSBAR
_LOGGER.info(STR_CROSSBAR)
_LOGGER.info("{0} :: if __name__ == '__main__':".format(_MODULENAME))
_LOGGER.info(STR_CROSSBAR)
# test from_ui_generate_form_and_base_class
_FORM_CLASS, _BASE_CLASS = ui_utils.from_ui_generate_form_and_base_class(_UI_FILE)
_LOGGER.info(_FORM_CLASS)
_LOGGER.info(_BASE_CLASS)
_LOGGER.info("Starting App: {0} ...".format(_TEST_APP_NAME))
while 0:
# Test 1, MainWindow with no widget (just the frame)
_MAINWINDOW = TemplateMainWindow(logger=_LOGGER)
_LOGGER.info(_MAINWINDOW.objectName())
_LOGGER.info(_MAINWINDOW.settings)
_LOGGER.info(_MAINWINDOW.settings.fileName())
_MAINWINDOW.setWindowTitle(_TEST_APP_NAME)
_MAINWINDOW.show()
break
while 0:
# test 2, demo forces a template widget to be created internally
_MAINWINDOW = TemplateMainWindow(logger=_LOGGER,
demo=True) #<-- template demo
_LOGGER.info(_MAINWINDOW.objectName())
_LOGGER.info(_MAINWINDOW.settings)
_LOGGER.info(_MAINWINDOW.settings.fileName())
_MAINWINDOW.setWindowTitle(_TEST_APP_NAME)
_MAINWINDOW.show()
break
while 1:
# test 3, add a custom tool widget
_MAINWINDOW = TemplateMainWindow(logger=_LOGGER)
_CUSTOM_WIDGET = TemplateToolWidget(parent=_MAINWINDOW)
_MAINWINDOW.add_custom_widget(_CUSTOM_WIDGET)
_LOGGER.info(_MAINWINDOW.objectName())
_LOGGER.info(_MAINWINDOW.settings)
_LOGGER.info(_MAINWINDOW.settings.fileName())
_MAINWINDOW.setWindowTitle(_TEST_APP_NAME)
_MAINWINDOW.show()
_MAINWINDOW.close() # test the close function
break
del _LOGGER
sys.exit(_MAINWINDOW.qapp.exec_())