import wx
import telnetlib
import win32gui
import win32com.client
import os
import sys
import time
import traceback
def process_is_running(proc_name):
import win32pdh
proc_name = os.path.splitext(proc_name)[0].lower()
junk, instances = win32pdh.EnumObjectItems(None,None,'Process', win32pdh.PERF_DETAIL_WIZARD)
for proc_inst in instances:
if (proc_inst.lower() == proc_name):
return True
return False
class MB_Sub_Frame(wx.Frame):
_top_mb_window_handle = None
def __init__(self, parent, app, id=-1, title="Motion Builder Tool", pos=(60, 120), size=(350, 200), name='frame', resize=True, style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.FRAME_NO_TASKBAR):
wx.Frame.__init__(self, parent, id, title, pos, size, style)
self.app = app
self.panel = None
self.initialPosOffset = pos
self._runningModal = False
if (not resize):
wx.Frame.ToggleWindowStyle(self, wx.RESIZE_BORDER)
bg_color = (197, 197, 197)
self.SetBackgroundStyle(wx.BG_STYLE_COLOUR)
self.SetBackgroundColour(wx.Color(bg_color[0], bg_color[1], bg_color[2]))
self.Bind(wx.EVT_CLOSE, self.on_close)
@classmethod
def create(cls, *args, **kw):
"""
Call this static class method to create a new instance of your subframe.
This will use the 3dsmax window as a parent for the current frame.
Limitation: If > 1 copy of 3dsmax is open, uses the first one it finds.
Could probably be fixed, however.
"""
if (not process_is_running('motionbuilder.exe')):
raise WindowsError('*** ERROR: MotionBuilder is not running')
else:
app = wx.GetApp()
if (app == None):
app = wx.App(redirect=False)
val = MB_Sub_Frame._get_top_mb_window()
topHandle = val[0]
if (topHandle == None):
raise WindowsError('*** ERROR: Motion Builder window handle not found.')
else:
windowPos = val[1]
toolFrame = wx.PreFrame()
toolFrame.AssociateHandle(topHandle)
toolFrame.PostCreate(toolFrame)
app.SetTopWindow(toolFrame)
try:
frame = cls(toolFrame, app, *args, **kw)
frame.Show(True)
except:
print cls.__name__
print traceback.format_exc()
frame = None
toolFrame.DissociateHandle()
return frame
@staticmethod
def _get_top_mb_window():
if MB_Sub_Frame._top_mb_window_handle is not None:
return MB_Sub_Frame._top_mb_window_handle
def callback(handle, winList):
winList.append(handle)
return True
windows = []
win32gui.EnumWindows(callback, windows)
for handle in windows:
title = win32gui.GetWindowText(handle)
if ('MotionBuilder 7.5' in title):
import win32con
window = win32gui.ShowWindow(handle, win32con.SW_MAXIMIZE)
pos = win32gui.GetWindowRect(handle)[:2]
MB_Sub_Frame._top_mb_window_handle = handle
return (handle, pos)
return None
def on_close(self, evt):
"""
Event handler for EVT_CLOSE event.
"""
self.Show(False)
self.Destroy()
win32gui.DestroyWindow(self.GetHandle())
win32gui.SetFocus(MB_Sub_Frame._top_mb_window_handle)
def show_modal_dialog(self, dlg):
"""
Method to display a modal dialog that also disables the 3dsmax window.
"""
mb_disabled = self._runningModal
if (not mb_disabled):
self._runningModal = True
top = MB_Sub_Frame._top_mb_window_handle win32gui.EnableWindow(top, False)
ret_val = dlg.ShowModal()
if (not mb_disabled): win32gui.EnableWindow(top, True)
self._runningModal = False
return ret_val
host = telnetlib.Telnet("127.0.0.1", 4242)
def mbPipe(command):
host.read_until('>>>', .01)
host.write(command + '\n')
raw = str(host.read_until('>>>', .1))
raw = raw.replace('\n\r>>>','')
raw = raw.replace('\r','')
rawArr = raw.split('\n')
return rawArr
class MyFrame(MB_Sub_Frame):
def __init__(self,parent,app):
MB_Sub_Frame.__init__(self, parent, app, id=-1, title='mbUI test',pos=(200, 150),size=(175,280))
self.selListBox = wx.ListBox(self, -1, choices=[],pos=(8,38),size=(150, 145))
self.selListBox.Bind(wx.EVT_LISTBOX, self.selListBoxChange)
self.translationLabel = wx.StaticText(self,-1,'Pos:',pos=(8,185))
self.rotationLabel = wx.StaticText(self,-1,'Rot:',pos=(8,200))
self.selItems = wx.Button(self, id=-1,label='Get Selected Items',pos=(8, 8),size=(150, 28))
self.selItems.Bind(wx.EVT_BUTTON, self.selItemsClick)
self.selItems.SetToolTip(wx.ToolTip("Gets all 'models' selected in Motion Builder"))
self.delItems = wx.Button(self, id=-1,label='Delete This Model',pos=(8, 217),size=(150, 28))
self.delItems.Bind(wx.EVT_BUTTON, self.delItemsClick)
self.delItems.SetToolTip(wx.ToolTip("Will delete selected models"))
def selItemsClick(self,event):
mbPipe("selectedModels = FBModelList()")
mbPipe("FBGetSelectedModels(selectedModels,None,True)")
self.selListBox.Set([])
for item in (mbPipe("for item in selectedModels: print item.Name")):
self.selListBox.Append(item)
def delItemsClick(self,event):
mbPipe('FBFindModelByName("' + str(self.selListBox.GetStringSelection()) + '").FBDelete()')
mbPipe("selectedModels = FBModelList()")
mbPipe("FBGetSelectedModels(selectedModels,None,True)")
self.selListBox.Set([])
for item in (mbPipe("for item in selectedModels: print item.Name")):
self.selListBox.Append(item)
def selListBoxChange(self,event):
trans = mbPipe('FBFindModelByName("' + str(self.selListBox.GetStringSelection()) + '").Translation')
rot = mbPipe('FBFindModelByName("' + str(self.selListBox.GetStringSelection()) + '").Rotation')
self.translationLabel.SetLabel(('Pos: ' + trans[0]))
self.rotationLabel.SetLabel(('Rot: ' + rot[0]))
def on_close(self, event):
print 'Shutting down...'
self.user_exit = True
self.Destroy()
application = wx.PySimpleApp()
window = MyFrame.create()
application.MainLoop()