3
0

base_widget.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. # coding:utf-8
  2. #!/usr/bin/python
  3. #
  4. # Copyright (c) Contributors to the Open 3D Engine Project.
  5. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  6. #
  7. # SPDX-License-Identifier: Apache-2.0 OR MIT
  8. #
  9. #
  10. # -------------------------------------------------------------------------
  11. from __future__ import unicode_literals
  12. # from builtins import str
  13. # built in's
  14. import os
  15. import sys
  16. import uuid
  17. import weakref
  18. import logging as _logging
  19. # 3rd Party
  20. from unipath import Path
  21. # azpy extensions
  22. import azpy.config_utils
  23. _config = azpy.config_utils.get_dccsi_config()
  24. settings = _config.get_config_settings(setup_ly_pyside=True)
  25. import PySide2.QtWidgets as QtWidgets
  26. import PySide2.QtCore as QtCore
  27. from shiboken2 import wrapInstance
  28. # -------------------------------------------------------------------------
  29. # global space debug flag
  30. _DCCSI_GDEBUG = settings.DCCSI_GDEBUG
  31. # global space debug flag
  32. _DCCSI_DEV_MODE = settings.DCCSI_DEV_MODE
  33. # global maya state (if we are running in maya with gui)
  34. # or another dcc tool with pyside2
  35. # TODO implement that check
  36. _G_PYSIDE2_DCC = None
  37. _MODULE_PATH = Path(__file__)
  38. _MODULENAME = 'azpy.shared.ui.azpy_base_widget'
  39. _LOGGER = _logging.getLogger(_MODULENAME)
  40. _LOGGER.debug('Something invoked :: {0}.'.format(_MODULENAME))
  41. # -------------------------------------------------------------------------
  42. class DccWidget(object):
  43. """This is an experimental Class to make a widget compatible with
  44. a number of PySide2/Python compatible DCC Tools like Maya and Houdini"""
  45. _LABEL_NAME = 'no name window' # Window display name
  46. _instances = list()
  47. # --constructor--------------------------------------------------------
  48. def __init__(self, parent=None, dcc_gui=_G_PYSIDE2_DCC, *args, **kwargs):
  49. # False or None, 'Maya', 'Houdini' ... or another pysdie2 dcc
  50. self._dcc_gui = dcc_gui
  51. self._name = '{0}_{1}'.format(self.__class__.__name__, uuid.uuid4())
  52. self._parent = parent
  53. self._parent = self._base_setup()
  54. # Init all baseclasses (including QWidget) of the main class
  55. try:
  56. super().__init__(*args, **kwargs)
  57. except Exception as Err:
  58. print(Err)
  59. self.__class__._instances.append(weakref.proxy(self))
  60. if isinstance(self, QtWidgets.QWidget):
  61. self.setParent(self._parent)
  62. # camel case because this is a Qt|Pyside2 widget method
  63. if self.objectName() == '':
  64. # Set a unique object name string so Maya can easily look it up
  65. self.setObjectName('{0}_{1}'.format(self._name))
  66. # -- properties -------------------------------------------------------
  67. @property
  68. def dcc_gui(self):
  69. return self._dcc_gui
  70. @dcc_gui.setter
  71. def dcc_gui(self, type):
  72. self._dcc_gui = type
  73. return self._dcc_gui
  74. @dcc_gui.getter
  75. def dcc_gui(self):
  76. return self._dcc_gui
  77. @property
  78. def parent(self):
  79. return self._parent
  80. @parent.setter
  81. def parent(self, type):
  82. self._parent = type
  83. return self._parent
  84. @parent.getter
  85. def parent(self):
  86. return self._parent
  87. # ---------------------------------------------------------------------
  88. def _base_setup(self, *args, **kwargs):
  89. '''TODO'''
  90. # if there is not a parent, we want a mainwindow to parent to
  91. if self.parent == None:
  92. self.parent = self._make_standalone_mainwindow()
  93. return self.parent
  94. def _make_standalone_mainwindow(self):
  95. '''Make a standalone mainwindow parent to existing Qapp
  96. We parent so that this Qwidget will not be auto-destroyed or garbage
  97. collected if the instance variable goes out of scope.
  98. If a Qapp doesn't exist, start one.
  99. '''
  100. original_parent = self._parent
  101. new_parent = None
  102. if self.dcc_gui:
  103. if self.dcc_gui == 'Maya':
  104. # import the Maya ui class
  105. import OpenMaya as omui
  106. # Parent under the main Maya window
  107. mainWindowPtr = omui.MQtUtil.mainWindow()
  108. new_parent = wrapInstance(long(mainWindowPtr), QMainWindow)
  109. elif self.dcc_gui == 'Houdini':
  110. pass # not implemented
  111. else:
  112. from azpy.shared.ui.templates import TemplateMainWindow
  113. new_parent = TemplateMainWindow()
  114. return new_parent
  115. def objectName(self):
  116. # stand in for Qt call on mixed objects, thus camelCase
  117. return None
  118. def show(self):
  119. # stand in for Qt call on mixed objects, thus camelCase
  120. return None
  121. def thing(self):
  122. # Make this widget appear as a standalone window even though it is parented
  123. if isinstance(self, QtWidgets.QDockWidget):
  124. self.setWindowFlags(QtCore.Qt.Dialog | QtCore.Qt.FramelessWindowHint)
  125. else:
  126. try:
  127. self.setWindowFlags(QtCore.Qt.Window)
  128. except:
  129. pass
  130. # Delete the parent QDockWidget if applicable
  131. if isinstance(original_parent, QtWidgets.QDockWidget):
  132. original_parent.close()
  133. # -------------------------------------------------------------------------
  134. class BaseQwidgetAzpy(object):
  135. """Inheret from to handle common base functionality for Qt Widgets
  136. Parents to a standalone Qapp and mainwindow if not explicitly provided
  137. Place this before the Qt Widget Class in inheretance order"""
  138. _LABEL_NAME = 'no name window' # Window display name
  139. _instances = list()
  140. _ORG_TAG = 'Amazon_Lumberyard'
  141. _APP_TAG = 'DCCsi'
  142. # --constructor--------------------------------------------------------
  143. def __init__(self,
  144. parent=None,
  145. logger=None,
  146. qapp=None,
  147. window_title=_LABEL_NAME,
  148. *args, **kwargs):
  149. """To DO"""
  150. self._name_uuid = '{0}_{1}'.format(self.__class__.__name__, uuid.uuid4())
  151. self._logger = logger
  152. if not self._logger:
  153. self._logger = _logging.getLogger(self._name_uuid)
  154. self._parent = parent
  155. self._qapp = qapp or QtWidgets.QApplication.instance()
  156. if self._qapp == None:
  157. self.logger.debug('No QApplication has been instantiated')
  158. self._qapp = self._base_setup(window_title)
  159. # Init all baseclasses (including QWidget) of the main class
  160. try:
  161. super(BaseQwidgetAzpy, self).__init__(*args, **kwargs)
  162. except Exception as Err:
  163. print(Err)
  164. self.__class__._instances.append(weakref.proxy(self))
  165. if isinstance(self, QtWidgets.QWidget):
  166. self.setParent(self._parent)
  167. # camel case because this is a Qt|Pyside2 widget method
  168. if self.objectName() == '':
  169. # Set a unique object name string so Maya can easily look it up
  170. self.setObjectName(self._name)
  171. # -- properties -------------------------------------------------------
  172. @property
  173. def parent(self):
  174. return self._parent
  175. @parent.setter
  176. def parent(self, type):
  177. self._parent = type
  178. return self._parent
  179. @parent.getter
  180. def parent(self):
  181. return self._parent
  182. @property
  183. def logger(self):
  184. return self._logger
  185. @logger.setter
  186. def logger(self, logger):
  187. self._logger = logger
  188. return self._logger
  189. @logger.getter
  190. def logger(self):
  191. return self._logger
  192. @property
  193. def qapp(self):
  194. return self._qapp
  195. @qapp.setter
  196. def qapp(self, qapp):
  197. self._qapp = qapp
  198. return self._qapp
  199. @qapp.getter
  200. def qapp(self):
  201. return self._qapp
  202. # ----------------------------------------------------------------------
  203. def objectName(self):
  204. # stand in for Qt call on mixed objects, thus camelCase
  205. return self._name_uuid
  206. def show(self):
  207. # stand in for Qt call on mixed objects, thus camelCase
  208. return None
  209. def _base_setup(self, *args, **kwargs):
  210. '''TODO'''
  211. # if there is not a parent, we want a mainwindow to parent to
  212. if self.parent == None:
  213. try:
  214. self.parent = self._make_standalone_app(self.objectName())
  215. except:
  216. self.parent = self._make_standalone_app(self._name_uuid)
  217. return self.parent
  218. def _make_standalone_app(self, name):
  219. useGUI = not '-no-gui' in sys.argv
  220. self.qapp = QtWidgets.QApplication(sys.argv) if useGUI else QtWidgets.QCoreApplication(sys.argv)
  221. self.qapp.setOrganizationName(self.__class__._ORG_TAG)
  222. self.qapp.setApplicationName('{app}:{tool}'.format(app=self.__class__._APP_TAG,
  223. tool=name))
  224. return self.qapp
  225. @QtCore.Slot()
  226. def closeEvent(self, *args, **kwargs):
  227. """Event which is run when window closes"""
  228. self.logger.debug("Method: {0}.{1}".format(self.__class__.__name__, 'closeEvent'))
  229. self.logger.debug("Closing: {0}".format(self.objectName()))
  230. self.__class__._instances.remove(self)
  231. self.qapp.instance().quit
  232. self.qapp.exit()
  233. # ----------------------------------------------------------------------
  234. # -------------------------------------------------------------------------
  235. class TestWidget(BaseQwidgetAzpy, QtWidgets.QPushButton):
  236. def __init__(self, parent=None, *args, **kwargs):
  237. # Init all baseclasses (including QWidget) of the main class
  238. try:
  239. super().__init__(*args, **kwargs)
  240. except Exception as Err:
  241. print(Err)
  242. try:
  243. self.logger.debug('{0}'.format(self.parent))
  244. except Exception as Err:
  245. print(Err)
  246. # self.setParent(parent)
  247. self.setText('Push Me')
  248. # -------------------------------------------------------------------------
  249. if __name__ == '__main__':
  250. """Run this file as main"""
  251. import sys
  252. _TEST_APP_NAME = '{0}-{1}'.format(_MODULENAME, 'TEST')
  253. _LOGGER = azpy.initialize_logger(_TEST_APP_NAME,
  254. log_to_file=True,
  255. default_log_level=_logging.DEBUG)
  256. from azpy.constants import STR_CROSSBAR
  257. _LOGGER.info(STR_CROSSBAR)
  258. _LOGGER.info("{0} :: if __name__ == '__main__':".format(_MODULENAME))
  259. _LOGGER.info(STR_CROSSBAR)
  260. # test raw BaseWidget
  261. _TEST_BASE_WIDGET = BaseQwidgetAzpy()
  262. _LOGGER.info(_TEST_BASE_WIDGET.objectName())
  263. _TEST_BASE_WIDGET.show() # this should do nothing,it is a dummy call
  264. # this call is replaced with version the QWidget
  265. _TEST_BASE_WIDGET.closeEvent() # mimic Qt close
  266. _TEST_BASE_WIDGET = None
  267. # NEED TO DELETE ^ Makes a Qapp
  268. _TEST_WIDGET = TestWidget()
  269. _LOGGER.info(_TEST_WIDGET.objectName())
  270. _TEST_WIDGET.show()
  271. del _LOGGER
  272. sys.exit(_TEST_WIDGET.qapp.exec_())
  273. # -------------------------------------------------------------------------