import os import wx import wx.lib.scrolledpanel as scrolled import re import traceback import win32gui, win32process, pythoncom from win32com.client import constants as c from win32com.client import constants false = 0 true = 1 xsi = Application log = xsi.LogMessage def XSILoadPlugin(in_reg): in_reg.Author = "James Parks" in_reg.Name = "jpPointOven" in_reg.Email = "arcsecond@gmail.com" in_reg.URL = "www.arcsecond.com" in_reg.Major = 1 in_reg.Minor = 0 in_reg.Categories = 'PointOven,Test' in_reg.RegisterCommand("jpPointOven", "jpPointOven") in_reg.RegisterMenu(c.siMenuTbGetPropertyID, "jpPointOven_Menu", False, False) return True def jpPointOven_Init(in_ctxt): oCmd = in_ctxt.Source oCmd.Description = "" oCmd.ReturnValue = True return True def jpPointOven_Execute(): jpFrame.create() return True def jpPointOven_Menu_Init(in_ctxt): oMenu = in_ctxt.Source oMenu.AddCommandItem("jpPointOven", "jpPointOven") return True #---------------------------- # That's the interesting bit: # This class can be put in a separate module and imported in the plugin for exemple. class XSISubFrame(wx.Frame): """ XSI wx SubFrame with special event bound to the close. Please inherit from this one to create a custom frame in XSI. In order to ensure a clean exit, please call the XSISubFrame.Close method to generate a EVT_CLOSE event. Don't forget to call the XSISubFrame.__init__ in your __init__! And don't forget to define the self.panel at the end of your .__init__! @author: Aloys Baillet """ _topLevelXSIWindowHandle = None @classmethod def create(cls, *args, **kw): """ Call this static class method to create a new instance of your subframe. This class method will use the XSI Top Level window as a parent for the current frame. """ app = wx.GetApp() if app is None: app = wx.App(redirect=False) topHandle = XSISubFrame._getXSITopLevelWindow() top = wx.PreFrame() top.AssociateHandle(topHandle) top.PostCreate(top) app.SetTopWindow(top) try: frame = cls(top, app, *args, **kw) frame.Show(True) except: log('An error occured during the instantiation of the %s frame class: %s'%(cls.__name__, traceback.format_exc()), c.siError) frame = None top.DissociateHandle() return frame @staticmethod def _getXSITopLevelWindow(): """ Returns the handle to the XSI top-level window """ if XSISubFrame._topLevelXSIWindowHandle is not None: return XSISubFrame._topLevelXSIWindowHandle def callback(handle, winList): winList.append(handle) return True wins = [] win32gui.EnumWindows(callback, wins) currentId = os.getpid() for handle in wins: tid, pid = win32process.GetWindowThreadProcessId(handle) if pid == currentId: title = win32gui.GetWindowText(handle) if title.startswith('SOFTIMAGE'): XSISubFrame._topLevelXSIWindowHandle = handle return handle return None def __init__(self, parent, app, id, title, pos=(150, 150), size=(350, 200), style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.FRAME_NO_TASKBAR|wx.FULL_REPAINT_ON_RESIZE, name='frame'): wx.Frame.__init__(self, parent, id, title, pos, size, style, name) self.app = app self.panel = None self._runningModal = False self.SetBackgroundStyle(wx.BG_STYLE_COLOUR) self.SetBackgroundColour(wx.Color(171, 168, 166)) self.Bind(wx.EVT_CLOSE, self.OnClose) self.Bind(wx.EVT_ACTIVATE, self.OnActivate) icon = wx.Icon('xsiIcon', wx.BITMAP_TYPE_ICO, 16, 16) icon.LoadFile(xsi.InstallationPath(c.siFactoryPath)+'\\xsi.ico', wx.BITMAP_TYPE_ICO) self.SetIcon(icon) def OnActivate(self, evt): """Event handler for activation. Used to detect modality in XSI""" if self._runningModal: return self.panel.Enable(win32gui.IsWindowEnabled(XSISubFrame._topLevelXSIWindowHandle)) evt.Skip() def OnClose(self, evt): """Event handler for EVT_CLOSE event.""" self.Show(False) self.Destroy() # This is because the regular wx Destroy waits for the application to destroy the window # But there is no wxApp running, so we do it ourselves win32gui.DestroyWindow(self.GetHandle()) win32gui.SetFocus(XSISubFrame._topLevelXSIWindowHandle) def showModalDialog(self, dlg): """ Method to display a modal dialog that disactivate XSI window. """ self._runningModal = True top = XSISubFrame._topLevelXSIWindowHandle win32gui.EnableWindow(top, False) dlgReturn = dlg.ShowModal() win32gui.EnableWindow(top, True) self._runningModal = False return dlgReturn def __del__(self): pass # End of the interesting bit #----------------- class jpFrame(XSISubFrame): def __init__(self, parent, app): XSISubFrame.__init__(self, parent, app, -1, 'jpPointOven', size=(100, 140)) self.panel = jpPanel(self) def OnClose(self, event): """ This method is bound by XSISubFrame to the EVT_CLOSE event. It shows a modal dialog before closing. Notice the win32gui hack to disable the XSI top-level window during the modal time. """ #dlg = wx.MessageDialog(None, 'Are you sure?', 'Sure?') #if self.showModalDialog(dlg) == wx.ID_OK: self.panel.onWindowClose() XSISubFrame.OnClose(self, event) class jpPanel(wx.Panel): _runningInstances = [] def __init__(self, parent): Application.LogMessage("This is a test: __init__") wx.Panel.__init__(self, parent, -1) self.createWidgets(parent) def createWidgets(self, parent): self.frame = parent ################### #make preferences ################### jpPointOvenPrefs = Application.Preferences.Categories("jpPointOven") if not jpPointOvenPrefs: oCus = Application.ActiveSceneRoot.AddCustomProperty( "tmp" ) oCus.AddParameter2("jpPointOvenPath", constants.siString,"\\\\Nitro\\vol1\\cgstor", 0,0,0,0, false, false, "poPath" ) Application.InstallCustomPreferences( oCus, "jpPointOven" ) Application.Preferences.Export(r"c:\jpPointOven.xsiprefs", "jpPointOven") # self.poPath = jpPointOvenPrefs.jpPointOvenPath.value; self.poPath = Application.Preferences.GetPreferenceValue("jpPointOven.jpPointOvenPath") ################ #Menu ################ menuBar = wx.MenuBar() fileMenu = wx.Menu() getPOpath_MENUITEM = fileMenu.Append(-1, "Set Path...") printPOpath_MENUITEM = fileMenu.Append(-1, "Print Path...") close_MENUITEM = fileMenu.Append(-1, "Close") menuBar.Append(fileMenu, "File") self.frame.SetMenuBar(menuBar) self.frame.Bind(wx.EVT_MENU, self.pickPOpath, getPOpath_MENUITEM) self.frame.Bind(wx.EVT_MENU, self.printPOpath, printPOpath_MENUITEM) self.frame.Bind(wx.EVT_MENU, self.OnClose, close_MENUITEM) ################# #Buttons 'n' Such ################# # getPOpathButton = wx.Button(self, -1, "Set Path...") # self.Bind(wx.EVT_BUTTON, self.pickPOpath, getPOpathButton) selectAllButton = wx.Button(self, -1, "Select*GEO") self.Bind(wx.EVT_BUTTON, self.selectAllGeo, selectAllButton) selectHeirButton = wx.Button(self, -1, "Select Heir *GEO") self.Bind(wx.EVT_BUTTON, self.selectHierGeo, selectHeirButton) # self.btn = wx.Button(self, -1, "Close") # self.Bind(wx.EVT_BUTTON, self.OnClose, self.btn) self.Bind(wx.EVT_CLOSE, self.OnClose) #scenesFile = r"\\Nitro\vol1\cgstor\AC07_Mucinex\Street\str_3D\PointOven\scenes.txt" scenesFile = (self.poPath + os.sep + "scenes.txt") scenes = self.jpReadLines(scenesFile) #scenes = ["test01", "test02", "test03"] self.scenesList = wx.Choice(self, -1, choices=scenes) deformButton = wx.Button(self, -1, "Deform Selected") self.Bind(wx.EVT_BUTTON, self.applyDeformers, deformButton) tID = wx.NewId() ################## #Sizer-ific ################## sizer = wx.BoxSizer(wx.VERTICAL) # sizer.Add(getPOpathButton, 0, wx.ALL) sizer.Add(selectAllButton, 0, wx.ALL) sizer.Add(selectHeirButton, 0, wx.ALL) sizer.Add(self.scenesList, 0, wx.ALL) sizer.Add(deformButton, 0, wx.ALL) # sizer.Add(self.btn, 0, wx.ALL) self.SetSizer(sizer) self.Layout() self.SetSize(sizer.GetSize()) self.SetAutoLayout(True) self.frozen = False self.Show(True) # self.SetupScrolling() jpPanel._runningInstances.append(self) def selectAllGeo(self,event): Application.LogMessage("This is a test: selectAllGeo") Application.LogMessage(event) Application.selectobj('*GEO') def selectHierGeo(self, event): Application.LogMessage("This is a test: selectHeirGeo") Application.SelectTree() model = Application.Selection[0] Application.selectobj(model.FindChildren('*GEO')) def jpReadLines(self, fileToRead): lines = [] badLines = [] if os.path.exists(fileToRead) == False: print "File Not Found" else: thisFile = file(fileToRead, "r+") badLines = thisFile.readlines() thisFile.close() for i in range(0, len(badLines)): lines.append(badLines[i].strip()) return lines def pickPOpath(self, event): Application.LogMessage("This is a test: pickPOpath") dialog = wx.DirDialog(None, "Choose a Path...", style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON) if dialog.ShowModal() == wx.ID_OK: self.poPath = dialog.GetPath() self.scenesList.Clear() scenesFile = (str(self.poPath) + os.sep + r"scenes.txt") newScenes = self.jpReadLines(scenesFile) self.scenesList.AppendItems(newScenes) # self.scenesList.Refresh() dialog.Destroy() #set preferences Application.Preferences.SetPreferenceValue("jpPointOven.jpPointOvenPath", self.poPath) def printPOpath(self,event): Application.LogMessage(str(self.poPath)) def applyDeformers(self, event): Application.LogMessage("This is a test: applyDeformers") path = self.poPath scene = self.scenesList.GetStringSelection() objs = [] for obj in Application.Selection: objs.append(str(obj)) Application.LogMessage(path) Application.LogMessage(scene) Application.LogMessage(objs) for thisObj in objs: #try: Application.LogMessage(str(thisObj)) Application.SetValue(str(thisObj) + ".polymsh.PO_XSI_Reader.Mute", 0, "") Application.LogMessage("Mute Set off") splitObj = re.split("\.", str(thisObj)) Application.LogMessage(splitObj) thisPath = (path + os.sep + scene + os.sep + str(splitObj[0]) + os.sep + str(splitObj[-1]) + ".mdd") Application.LogMessage(thisPath) Application.SetValue(str(thisObj) + ".polymsh.PO_XSI_Reader.FileName", (path + os.sep + scene + os.sep + str(splitObj[0]) + os.sep + str(splitObj[-1]) + ".mdd"), "") #except: # Application.LogMessage("Something went wrong") # Application.ApplyOp("POXSI", str(thisObj), "siUnspecified", "siPersistentOperation", "", 0) # Application.AddExpr((str(thisObj) + ".polymsh.PO_XSI_Reader.POTime"), "T", 1) # Application.SetValue(str(thisObj) + ".polymsh.PO_XSI_Reader.Mute", 0, "") # splitObj = re.split("\.", str(thisObj)) # thisPath = (path + os.sep + scene + os.sep + str(splitObj[0]) + os.sep + str(splitObj[-1]) + ".mdd") # Application.LogMessage(thisPath) # Application.SetValue(str(thisObj) + ".polymsh.PO_XSI_Reader.FileName", (path + os.sep + scene + os.sep + str(splitObj[0]) + os.sep + str(splitObj[-1]) + ".mdd"), "") def onWindowClose(self): jpPanel._runningInstances.remove(self) def OnClose(self, evt): """Event handler for the button click.""" self.frame.Close()