From 5340c0f7e8863128a1e0f543eb985dff6d9325d5 Mon Sep 17 00:00:00 2001 From: Ana Gomez Date: Wed, 9 May 2012 12:14:28 +0200 Subject: [PATCH 1/4] SISignals is a singleton that is able to register the used signals --- src/pyqt_example.py | 323 ++++++++++++++++++++++---------------------- src/qtevents.py | 15 +- src/sisignals.py | 58 +++++++- 3 files changed, 215 insertions(+), 181 deletions(-) diff --git a/src/pyqt_example.py b/src/pyqt_example.py index 0390284..147edd5 100644 --- a/src/pyqt_example.py +++ b/src/pyqt_example.py @@ -1,165 +1,160 @@ -import os -import sip - -from PyQt4 import uic - -from PyQt4.QtCore import Qt -from PyQt4.QtCore import pyqtSignal -from PyQt4.QtCore import pyqtSlot - -from PyQt4.QtGui import QDialog -from PyQt4.QtGui import QWidget -from PyQt4.QtGui import QPushButton -from PyQt4.QtGui import QLineEdit -from PyQt4.QtGui import QVBoxLayout -from PyQt4.QtGui import QMenu -from PyQt4.QtGui import QCursor - - -class ExampleDialog( QDialog ): - def __init__( self, parent ): - QDialog.__init__( self, parent ) - - self.setGeometry( 100, 100, 200, 100 ) - self.setWindowTitle( "Hello World" ) - self.setToolTip( "This is a QWidget widget" ) - - self.btn = QPushButton( "Log Text", self ) - self.btn.setToolTip( "This is a QPushButton widget" ) - self.btn.resize( self.btn.sizeHint() ) - self.btn.clicked.connect( self.logText ) - - self.lineedit = QLineEdit( "Hello World", self ) - self.lineedit.setToolTip( "Type Something" ) - - layout = QVBoxLayout( self ) - layout.addWidget( self.lineedit ) - layout.addWidget( self.btn ) - - def logText( self ): - Application.LogMessage( self.lineedit.text() ) - -class ExampleSignalSlot( ExampleDialog ): - def __init__( self, parent ): - ExampleDialog.__init__( self,parent ) - self.setWindowTitle( "Signal/Slot Example" ) - self.lineedit.setText( "" ) - - # module containing sievents mapped to pyqtsignals - from sisignals import signals, muteSIEvent - - # connect the siActivate signal to the activate slot - signals.siActivate.connect( self.activate ) - muteSIEvent( "siActivate", False ) - - # connect the siPassChange signal to the passChanged slot - signals.siPassChange.connect( self.passChanged ) - muteSIEvent( "siPassChange", False ) - - def activate( self, state = None ): - if state is not None: - if state: - self.lineedit.setText( "Welcome Back!" ) - else: - self.lineedit.setText( "Good Bye!") - - def passChanged( self, targetPass = "" ): - self.lineedit.setText( targetPass ) - - def closeEvent( self, event ): - # disconnect signals from slots when you close the widget - # muteSIEvent() can be used to mute the signals softimage events send - # but be careful if another widget exists and is using them - from sisignals import signals, muteSIEvent - signals.siActivate.disconnect( self.activate ) - signals.siPassChange.disconnect( self.passChanged ) - #muteSIEvent( "siActivate", True ) - #muteSIEvent( "siPassChange", True ) - -class ExampleMenu( QMenu ): - def __init__( self, parent ): - QMenu.__init__( self, parent ) - - # add actions and a separator - hello = self.addAction("Print 'Hello!'") - self.addSeparator() - world = self.addAction("Print 'World!'") - - # connect to the individual action's signal - hello.triggered.connect( self.hello ) - world.triggered.connect( self.world ) - - # connect to the menu level signal - self.triggered.connect( self.menuTrigger ) - - def hello( self ): - print( "Hello!" ) - - def world( self ): - print( "World!" ) - - def menuTrigger( self, action ): - if action.text() == "Print 'Hello!'": - print( "You clicked, Print 'Hello!'" ) - elif action.text() == "Print 'World!'": - print( "You clicked, Print 'World!'" ) - -class ExampleUIFile( QDialog ): - def __init__( self, parent, uifilepath ): - QDialog.__init__( self, parent ) - - # load ui file - self.ui = uic.loadUi( uifilepath, self ) - - # connect to the createCube function - self.ui.uiCreateCube.clicked.connect( self.createCube ) - - def createCube( self ): - cube = Application.CreatePrim("Cube", "MeshSurface", str(self.uiCubeName.text()), "") - cube.Length.Value = self.uiCubeLength.value() - -def XSILoadPlugin( in_reg ): - in_reg.Name = "PyQt_Example" - in_reg.Author = "Steven Caron" - in_reg.RegisterCommand( "ExampleDialog" ) - in_reg.RegisterCommand( "ExampleSignalSlot" ) - in_reg.RegisterCommand( "ExampleMenu" ) - in_reg.RegisterCommand( "ExampleUIFile" ) - -def ExampleDialog_Execute(): - """a simple example dialog showing basic functionality of the pyqt for softimage plugin""" - sianchor = Application.getQtSoftimageAnchor() - sianchor = sip.wrapinstance( long(sianchor), QWidget ) - dialog = ExampleDialog( sianchor ) - dialog.show() - -def ExampleSignalSlot_Execute(): - """a simple example showing softimage events triggering pyqt signals""" - sianchor = Application.getQtSoftimageAnchor() - sianchor = sip.wrapinstance( long(sianchor), QWidget ) - dialog = ExampleSignalSlot( sianchor ) - dialog.show() - -def ExampleMenu_Execute(): - """a simple example showing the use of a qmenu""" - sianchor = Application.getQtSoftimageAnchor() - sianchor = sip.wrapinstance( long(sianchor), QWidget ) - menu = ExampleMenu( sianchor ) - - # notice the use of QCursor and exec_ call - menu.exec_(QCursor.pos()) - -def ExampleUIFile_Execute(): - """a simple example showing the use of a .ui file created using QtDesigner""" - - # find plugin to get the path to the example ui file - plugin = Application.Plugins("PyQt_Example") - if plugin is None: - return False - - sianchor = Application.getQtSoftimageAnchor() - sianchor = sip.wrapinstance( long(sianchor), QWidget ) - uifilepath = os.path.join(plugin.OriginPath, "exampleui.ui") - dialog = QDialog(sianchor) - dialog = ExampleUIFile( dialog, uifilepath ) +import os +import sip + +from PyQt4 import uic + +from PyQt4.QtCore import Qt +from PyQt4.QtCore import pyqtSignal +from PyQt4.QtCore import pyqtSlot + +from PyQt4.QtGui import QDialog +from PyQt4.QtGui import QWidget +from PyQt4.QtGui import QPushButton +from PyQt4.QtGui import QLineEdit +from PyQt4.QtGui import QVBoxLayout +from PyQt4.QtGui import QMenu +from PyQt4.QtGui import QCursor + + +class ExampleDialog( QDialog ): + def __init__( self, parent ): + QDialog.__init__( self, parent ) + + self.setGeometry( 100, 100, 200, 100 ) + self.setWindowTitle( "Hello World" ) + self.setToolTip( "This is a QWidget widget" ) + + self.btn = QPushButton( "Log Text", self ) + self.btn.setToolTip( "This is a QPushButton widget" ) + self.btn.resize( self.btn.sizeHint() ) + self.btn.clicked.connect( self.logText ) + + self.lineedit = QLineEdit( "Hello World", self ) + self.lineedit.setToolTip( "Type Something" ) + + layout = QVBoxLayout( self ) + layout.addWidget( self.lineedit ) + layout.addWidget( self.btn ) + + def logText( self ): + Application.LogMessage( self.lineedit.text() ) + +class ExampleSignalSlot( ExampleDialog ): + def __init__( self, parent ): + ExampleDialog.__init__( self,parent ) + self.setWindowTitle( "Signal/Slot Example" ) + self.lineedit.setText( "" ) + + # module containing sievents mapped to pyqtsignals + from sisignals import signals + + # connect the siActivate signal to the activate slot and unmute the event if necessary. + signals.connect('siActivate', self.activate ) + + # connect the siPassChange signal to the passChanged slot and unmute the event if necessary. + signals.connect('siPassChange', self.passChanged ) + + def activate( self, state = None ): + if state is not None: + if state: + self.lineedit.setText( "Welcome Back!" ) + else: + self.lineedit.setText( "Good Bye!") + + def passChanged( self, targetPass = "" ): + self.lineedit.setText( targetPass ) + + def closeEvent( self, event ): + # Disconnect signals from slots when you close the widget. + # Softimage signals are muted if no other widgets are using them. + from sisignals import signals + signals.disconnect('siActivate', self.activate ) + signals.disconnect('siPassChange', self.passChanged ) + +class ExampleMenu( QMenu ): + def __init__( self, parent ): + QMenu.__init__( self, parent ) + + # add actions and a separator + hello = self.addAction("Print 'Hello!'") + self.addSeparator() + world = self.addAction("Print 'World!'") + + # connect to the individual action's signal + hello.triggered.connect( self.hello ) + world.triggered.connect( self.world ) + + # connect to the menu level signal + self.triggered.connect( self.menuTrigger ) + + def hello( self ): + print( "Hello!" ) + + def world( self ): + print( "World!" ) + + def menuTrigger( self, action ): + if action.text() == "Print 'Hello!'": + print( "You clicked, Print 'Hello!'" ) + elif action.text() == "Print 'World!'": + print( "You clicked, Print 'World!'" ) + +class ExampleUIFile( QDialog ): + def __init__( self, parent, uifilepath ): + QDialog.__init__( self, parent ) + + # load ui file + self.ui = uic.loadUi( uifilepath, self ) + + # connect to the createCube function + self.ui.uiCreateCube.clicked.connect( self.createCube ) + + def createCube( self ): + cube = Application.CreatePrim("Cube", "MeshSurface", str(self.uiCubeName.text()), "") + cube.Length.Value = self.uiCubeLength.value() + +def XSILoadPlugin( in_reg ): + in_reg.Name = "PyQt_Example" + in_reg.Author = "Steven Caron" + in_reg.RegisterCommand( "ExampleDialog" ) + in_reg.RegisterCommand( "ExampleSignalSlot" ) + in_reg.RegisterCommand( "ExampleMenu" ) + in_reg.RegisterCommand( "ExampleUIFile" ) + +def ExampleDialog_Execute(): + """a simple example dialog showing basic functionality of the pyqt for softimage plugin""" + sianchor = Application.getQtSoftimageAnchor() + sianchor = sip.wrapinstance( long(sianchor), QWidget ) + dialog = ExampleDialog( sianchor ) + dialog.show() + +def ExampleSignalSlot_Execute(): + """a simple example showing softimage events triggering pyqt signals""" + sianchor = Application.getQtSoftimageAnchor() + sianchor = sip.wrapinstance( long(sianchor), QWidget ) + dialog = ExampleSignalSlot( sianchor ) + dialog.show() + +def ExampleMenu_Execute(): + """a simple example showing the use of a qmenu""" + sianchor = Application.getQtSoftimageAnchor() + sianchor = sip.wrapinstance( long(sianchor), QWidget ) + menu = ExampleMenu( sianchor ) + + # notice the use of QCursor and exec_ call + menu.exec_(QCursor.pos()) + +def ExampleUIFile_Execute(): + """a simple example showing the use of a .ui file created using QtDesigner""" + + # find plugin to get the path to the example ui file + plugin = Application.Plugins("PyQt_Example") + if plugin is None: + return False + + sianchor = Application.getQtSoftimageAnchor() + sianchor = sip.wrapinstance( long(sianchor), QWidget ) + uifilepath = os.path.join(plugin.OriginPath, "exampleui.ui") + dialog = QDialog(sianchor) + dialog = ExampleUIFile( dialog, uifilepath ) dialog.show() \ No newline at end of file diff --git a/src/qtevents.py b/src/qtevents.py index aefc633..3a3bf84 100644 --- a/src/qtevents.py +++ b/src/qtevents.py @@ -2,7 +2,7 @@ from win32com.client import Dispatch as disp from win32com.client import constants as C -si = disp('XSI.Application') +si = disp('XSI.Application').Application # Create a mapping of virtual keys import win32con @@ -276,13 +276,9 @@ def XSILoadPlugin( in_reg ): in_reg.RegisterEvent( "QtEvents_SelectionChange", C.siOnSelectionChange ) in_reg.RegisterEvent( "QtEvents_ValueChange", C.siOnValueChange ) - # mute immediately. the dialog is responsble for turning the events it needs on - events = si.EventInfos - from sisignals import EVENT_MAPPING - for key,value in EVENT_MAPPING.iteritems(): - event = events( value ) - if si.ClassName( event ) == "EventInfo": - event.Mute = True + # Clean the registry and mute the events immediately. + from sisignals import signals + signals.reload() return True @@ -392,5 +388,4 @@ def QtEvents_SelectionChange_OnEvent( in_ctxt ): def QtEvents_ValueChange_OnEvent( in_ctxt ): from sisignals import signals - signals.siValueChange.emit( in_ctxt.GetAttribute( "FullName" ) ) - + signals.siValueChange.emit( in_ctxt.GetAttribute( "FullName" ) ) \ No newline at end of file diff --git a/src/sisignals.py b/src/sisignals.py index 502cb35..9ea975c 100644 --- a/src/sisignals.py +++ b/src/sisignals.py @@ -3,7 +3,7 @@ from win32com.client import Dispatch as disp from win32com.client import constants as C -si = disp('XSI.Application') +si = disp('XSI.Application').Application EVENT_MAPPING = { #pyqtsignal : softimage event @@ -41,9 +41,10 @@ class SISignals( QObject ): """ - class for mapping softimage events to pyqt signals + Class for mapping softimage events to pyqt signals not all context attributes are passed as signal arguments, add more as needed - currently all signals are expected to be 'siOnEnd' versions of softimage events + currently all signals are expected to be 'siOnEnd' versions of softimage events. + It is implemented as a singleton and registers which signals are in used with which slot. """ # add more pyqtsignals that map to softimage events here @@ -79,14 +80,57 @@ class for mapping softimage events to pyqt signals siValueChange = pyqtSignal(str) # siOnValueChange + _instance = None + + _connections = {} + def __init__(self): QObject.__init__(self) self.setObjectName( "siSignals" ) + def __new__(cls, *args, **kwargs): + if not cls._instance: + cls._instance = super(SISignals, cls).__new__(cls, *args, **kwargs) + return cls._instance + + def connect(self, signal, function): + if hasattr(self, signal): + if signal in self._connections: + slots = self._connections[signal] + if function not in slots: + getattr(self, signal).connect(function) + slots.append(function) + else: + getattr(self, signal).connect(function) + self._connections[signal] = [function] + muteSIEvent(signal, False) + + def disconnect(self, signal, function): + if hasattr(self, signal): + getattr(self, signal).disconnect(function) + + if signal in self._connections: + slots = self._connections[signal] + if function in slots: + slots.remove(function) + if not len(slots): + self._connections.pop(signal) + muteSIEvent(signal, True) + + def emit(self, signal, *args): + if hasattr(self, signal): + getattr(self,signal).emit(*args) + + def reload(self): + self._connections = {} + for signal in EVENT_MAPPING: + muteSIEvent(signal, True) + signals = SISignals() -def muteSIEvent( event, state = True ): +def muteSIEvent(signal, state=True): events = si.EventInfos - event = events( EVENT_MAPPING[event] ) - if si.ClassName( event ) == "EventInfo": - event.Mute = state \ No newline at end of file + event = events(EVENT_MAPPING[signal]) + if si.ClassName(event) == "EventInfo": + event.Mute = state + \ No newline at end of file From d229418716a0786228365c8232624b762dc04f8a Mon Sep 17 00:00:00 2001 From: Ana Gomez Date: Wed, 9 May 2012 12:24:00 +0200 Subject: [PATCH 2/4] Change in a comment --- src/pyqt_example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyqt_example.py b/src/pyqt_example.py index 147edd5..d295fce 100644 --- a/src/pyqt_example.py +++ b/src/pyqt_example.py @@ -66,7 +66,7 @@ def passChanged( self, targetPass = "" ): def closeEvent( self, event ): # Disconnect signals from slots when you close the widget. - # Softimage signals are muted if no other widgets are using them. + # Softimage events are muted if no other widgets are using them. from sisignals import signals signals.disconnect('siActivate', self.activate ) signals.disconnect('siPassChange', self.passChanged ) From 385b2ff4662a72e91bcbd18d57effa7b86a7ba2d Mon Sep 17 00:00:00 2001 From: Ana Gomez Date: Thu, 10 May 2012 13:43:49 +0200 Subject: [PATCH 3/4] reload renamed to reset and signals emited with my method --- src/qtevents.py | 42 +++++++++++++++++++++--------------------- src/sisignals.py | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/qtevents.py b/src/qtevents.py index 3a3bf84..3851670 100644 --- a/src/qtevents.py +++ b/src/qtevents.py @@ -278,7 +278,7 @@ def XSILoadPlugin( in_reg ): # Clean the registry and mute the events immediately. from sisignals import signals - signals.reload() + signals.reset() return True @@ -308,15 +308,15 @@ def QtEvents_KeyUp_OnEvent( in_ctxt ): def QtEvents_Activate_OnEvent( in_ctxt ): from sisignals import signals - signals.siActivate.emit( in_ctxt.GetAttribute( "State" ) ) + signals.emit( "siActivate", in_ctxt.GetAttribute( "State" ) ) def QtEvents_FileExport_OnEvent( in_ctxt ): from sisignals import signals - signals.siFileExport.emit( in_ctxt.GetAttribute( "FileName" ) ) + signals.emit( "siFileExport", in_ctxt.GetAttribute( "FileName" ) ) def QtEvents_FileImport_OnEvent( in_ctxt ): from sisignals import signals - signals.siFileImport.emit( in_ctxt.GetAttribute( "FileName" ) ) + signals.emit( "siFileImport", in_ctxt.GetAttribute( "FileName" ) ) #def QtEvents_CustomFileExport_OnEvent( in_ctxt ): @@ -324,68 +324,68 @@ def QtEvents_FileImport_OnEvent( in_ctxt ): def QtEvents_RenderFrame_OnEvent( in_ctxt ): from sisignals import signals - signals.siRenderFrame.emit( in_ctxt.GetAttribute( "FileName" ), in_ctxt.GetAttribute( "Frame" ) ) + signals.emit( "siRenderFrame", in_ctxt.GetAttribute( "FileName" ), in_ctxt.GetAttribute( "Frame" ) ) def QtEvents_RenderSequence_OnEvent( in_ctxt ): from sisignals import signals - signals.siRenderSequence.emit( in_ctxt.GetAttribute( "FileName" ), in_ctxt.GetAttribute( "Frame" ) ) + signals.emit( "siRenderSequence", in_ctxt.GetAttribute( "FileName" ), in_ctxt.GetAttribute( "Frame" ) ) def QtEvents_RenderAbort_OnEvent( in_ctxt ): from sisignals import signals - signals.siRenderAbort.emit( in_ctxt.GetAttribute( "FileName" ), in_ctxt.GetAttribute( "Frame" ) ) + signals.emit( "siRenderAbort", in_ctxt.GetAttribute( "FileName" ), in_ctxt.GetAttribute( "Frame" ) ) def QtEvents_PassChange_OnEvent( in_ctxt ): from sisignals import signals - signals.siPassChange.emit( in_ctxt.GetAttribute( "TargetPass" ) ) + signals.emit( "siPassChange", in_ctxt.GetAttribute( "TargetPass" ) ) def QtEvents_SceneOpen_OnEvent( in_ctxt ): from sisignals import signals - signals.siSceneOpen.emit( in_ctxt.GetAttribute( "FileName" ) ) + signals.emit( "siSceneOpen", in_ctxt.GetAttribute( "FileName" ) ) def QtEvents_SceneSaveAs_OnEvent( in_ctxt ): from sisignals import signals - signals.siSceneSaveAs.emit( in_ctxt.GetAttribute( "FileName" ) ) + signals.emit( "siSceneSaveAs", in_ctxt.GetAttribute( "FileName" ) ) def QtEvents_SceneSave_OnEvent( in_ctxt ): from sisignals import signals - signals.siSceneSave.emit( in_ctxt.GetAttribute( "FileName" ) ) + signals.emit( "siSceneSave", in_ctxt.GetAttribute( "FileName" ) ) def QtEvents_ChangeProject_OnEvent( in_ctxt ): from sisignals import signals - signals.siChangeProject.emit( in_ctxt.GetAttribute( "NewProjectPath" ) ) + signals.emit( "siChangeProject", in_ctxt.GetAttribute( "NewProjectPath" ) ) def QtEvents_ConnectShader_OnEvent( in_ctxt ): from sisignals import signals - signals.siConnectShader.emit( in_ctxt.GetAttribute( "Source" ), in_ctxt.GetAttribute( "Target" ) ) + signals.emit( "siConnectShader", in_ctxt.GetAttribute( "Source" ), in_ctxt.GetAttribute( "Target" ) ) def QtEvents_DisconnectShader_OnEvent( in_ctxt ): from sisignals import signals - signals.siDisconnectShader.emit( in_ctxt.GetAttribute( "Source" ), in_ctxt.GetAttribute( "Target" ) ) + signals.emit( "siDisconnectShader", in_ctxt.GetAttribute( "Source" ), in_ctxt.GetAttribute( "Target" ) ) def QtEvents_CreateShader_OnEvent( in_ctxt ): from sisignals import signals - signals.siCreateShader.emit( in_ctxt.GetAttribute( "Shader" ), in_ctxt.GetAttribute( "ProgID" ) ) + signals.emit( "siCreateShader", in_ctxt.GetAttribute( "Shader" ), in_ctxt.GetAttribute( "ProgID" ) ) def QtEvents_SourcePathChange_OnEvent( in_ctxt ): from sisignals import signals - signals.siSourcePathChange.emit( in_ctxt.GetAttribute( "FileName" ) ) + signals.emit( "siSourcePathChange", in_ctxt.GetAttribute( "FileName" ) ) def QtEvents_DragAndDrop_OnEvent( in_ctxt ): from sisignals import signals - signals.siDragAndDrop.emit( in_ctxt.GetAttribute( "DragSource" ) ) + signals.emit( "siDragAndDrop", in_ctxt.GetAttribute( "DragSource" ) ) def QtEvents_ObjectAdded_OnEvent( in_ctxt ): from sisignals import signals - signals.siObjectAdded.emit( in_ctxt.GetAttribute( "Objects" ) ) + signals.emit( "siObjectAdded", in_ctxt.GetAttribute( "Objects" ) ) def QtEvents_ObjectRemoved_OnEvent( in_ctxt ): from sisignals import signals - signals.siObjectRemoved.emit( in_ctxt.GetAttribute( "Objects" ) ) + signals.emit( "siObjectRemoved", in_ctxt.GetAttribute( "Objects" ) ) def QtEvents_SelectionChange_OnEvent( in_ctxt ): from sisignals import signals - signals.siSelectionChange.emit( in_ctxt.GetAttribute( "ChangeType" ) ) + signals.emit( "siSelectionChange", in_ctxt.GetAttribute( "ChangeType" ) ) def QtEvents_ValueChange_OnEvent( in_ctxt ): from sisignals import signals - signals.siValueChange.emit( in_ctxt.GetAttribute( "FullName" ) ) \ No newline at end of file + signals.emit( "siValueChange", in_ctxt.GetAttribute( "FullName" ) ) \ No newline at end of file diff --git a/src/sisignals.py b/src/sisignals.py index 9ea975c..2e5ec4f 100644 --- a/src/sisignals.py +++ b/src/sisignals.py @@ -121,7 +121,7 @@ def emit(self, signal, *args): if hasattr(self, signal): getattr(self,signal).emit(*args) - def reload(self): + def reset(self): self._connections = {} for signal in EVENT_MAPPING: muteSIEvent(signal, True) From dee806d8e056c3402894f34162d2716c62a23e64 Mon Sep 17 00:00:00 2001 From: Ana Gomez Date: Wed, 22 Aug 2012 11:51:06 +0200 Subject: [PATCH 4/4] - New signals: siUndo and siRedo. - Signal siValueChange is sent with the full name of the parameter, the parameter object and the old value. --- src/qtevents.py | 19 ++++++++++++++++++- src/sisignals.py | 8 +++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/qtevents.py b/src/qtevents.py index 3851670..d1d1213 100644 --- a/src/qtevents.py +++ b/src/qtevents.py @@ -276,6 +276,11 @@ def XSILoadPlugin( in_reg ): in_reg.RegisterEvent( "QtEvents_SelectionChange", C.siOnSelectionChange ) in_reg.RegisterEvent( "QtEvents_ValueChange", C.siOnValueChange ) + # events added in 2012, err v10.0 + if xsi_version() >= 10.0: + in_reg.RegisterEvent( "QtEvents_Undo", C.siOnEndCommand) + in_reg.RegisterEvent( "QtEvents_Redo", C.siOnEndCommand) + # Clean the registry and mute the events immediately. from sisignals import signals signals.reset() @@ -388,4 +393,16 @@ def QtEvents_SelectionChange_OnEvent( in_ctxt ): def QtEvents_ValueChange_OnEvent( in_ctxt ): from sisignals import signals - signals.emit( "siValueChange", in_ctxt.GetAttribute( "FullName" ) ) \ No newline at end of file + signals.emit( "siValueChange", in_ctxt.GetAttribute( "FullName" ), in_ctxt.GetAttribute( "Object" ), in_ctxt.GetAttribute( "PreviousValue" )) + +def QtEvents_Undo_OnEvent( in_ctxt ): + o_command = in_ctxt.GetAttribute( "Command" ) + if o_command.ScriptingName == "Undo": + from sisignals import signals + signals.emit( "siUndo" ) + +def QtEvents_Redo_OnEvent( in_ctxt ): + o_command = in_ctxt.GetAttribute( "Command" ) + if o_command.ScriptingName == "Redo": + from sisignals import signals + signals.emit( "siRedo" ) \ No newline at end of file diff --git a/src/sisignals.py b/src/sisignals.py index 2e5ec4f..ad41868 100644 --- a/src/sisignals.py +++ b/src/sisignals.py @@ -37,6 +37,9 @@ "siSourcePathChange" : "QtEvents_SourcePathChange", "siValueChange" : "QtEvents_ValueChange", + + "siUndo": "QtEvents_Undo", + "siRedo": "QtEvents_Redo", } class SISignals( QObject ): @@ -78,8 +81,11 @@ class SISignals( QObject ): siSourcePathChange = pyqtSignal(str) # siOnSourcePathChange - siValueChange = pyqtSignal(str) # siOnValueChange + siValueChange = pyqtSignal(str, object, object) # siOnValueChange + siUndo = pyqtSignal() # siOnEndCommand (undo) + siRedo = pyqtSignal() # siOnEndCommand (redo) + _instance = None _connections = {}