""" current v2.4 Script Loader , Kevin Flynn, flynny85@gmail.com , tech animator. Goals: - Simple Install + install to shelf button. - Mac / PC in-dependant. - Flexible, 1)Button text, 2)Icon, or 3)dock-able , 4)mini mode. - Local version of scripts system? Just in-case. - will display the icon for a script if its named the same. - bug fixes: window and layout items now no longer use hard coded names.. unix paths should play nicely """ versionTxt = 'Script Loader V2.4' # proc imports here: import maya.cmds as cmds import maya.mel as mel import os import posixpath import shutil import sys # Global Values here: Scrpt_Ldr_Win_W_H = [190 , 180] # Window UI Settings Scrpt_Ldr_Colour_1 = [.7 , .7 , -.1] # Window UI Settings Scrpt_Ldr_Colour_2 = [.7 , .7 , -.1] # Window UI Settings Scrpt_Ldr_Colour_3 = [.7 , .7 , -.1] # Window UI Settings Scrpt_Ldr_Server_UserPref = [] # The servers prefs Scrpt_Ldr_Local_UserPref = [] # The local users prefs Scrpt_Ldr_Docked = False Scrpt_Ldr_DockUI = '' Scrpt_Ldr_IconUI = False Scrpt_Ldr_ScrollUI = '' Script_Ldr_ScriptCol = [.4 , .4 , .4] Script_Ldr_ScriptColMel = [.3 , 0 , 0] Script_Ldr_ScriptColPy = [0 , .3 , 0] Script_Ldr_ScriptColAll = [ Script_Ldr_ScriptColMel , Script_Ldr_ScriptColPy ] Scrpt_Ldr_Local_FolderPath = 'Choose Folder' # Users local script dump folder Scrpt_Ldr_FolderNotShown = [ 'Hidden' ] # folder from the server that will not be shown, but still copied. Script_Ldr_IconTypes = [ 'bmp', 'gif', 'jpg', 'jpeg', 'png', 'pbm', 'pgm', 'ppm', 'xbm', 'svg', 'xpm' ] # accepted image types. Script_Ldr_FileTypes = [ '.mel' , '.py' ] # accepted file types. def Script_Loader_WinUI(): global Scrpt_Ldr_WinUI global Scrpt_Ldr_Local_FolderPath global Scrpt_Ldr_PaneAttachUI global Scrpt_Ldr_ScrollUI global Scrpt_Ldr_SettingsUI Scrpt_Ldr_Win = "Scrpt_Ldr_Win" if cmds.window('Scrpt_Ldr_Win', exists = True ): cmds.deleteUI('Scrpt_Ldr_Win', window = True ) cmds.windowPref( 'Scrpt_Ldr_Win', remove = True ) Scrpt_Ldr_WinUI = cmds.window( Scrpt_Ldr_Win , widthHeight = Scrpt_Ldr_Win_W_H , rtf = True , toolbox = True ) Scrpt_Ldr_PaneAttachUI = cmds.paneLayout( 'master_Scrpt_Ldr_Win' , parent = 'Scrpt_Ldr_Win' , shp = True , configuration='horizontal2' ) cmds.paneLayout( Scrpt_Ldr_PaneAttachUI , edit = True , ps = [ 1 , 0 , 1 ] ) cmds.rowColumnLayout( 'master_Scrpt_Ldr_Win_ColsHeader' , numberOfColumns = 2 , parent = Scrpt_Ldr_PaneAttachUI ) cmds.rowColumnLayout( 'master_Scrpt_Ldr_Win_ColsHeader_Left' , numberOfColumns = 1 , parent = 'master_Scrpt_Ldr_Win_ColsHeader' ) cmds.button( 'Script_Loader_WinUI_Btn_Rfrsh' , label = ( 'Script Loader' ) , align = 'left' , ann = ( 'Click to refresh scripts : ' + versionTxt ) , width = ( ( Scrpt_Ldr_Win_W_H[0] / 10 ) * 8 ) , parent = 'master_Scrpt_Ldr_Win_ColsHeader_Left' , command = 'Script_Loader_Refresh()' ) cmds.rowColumnLayout( 'master_Scrpt_Ldr_Win_ColsHeader_Right' , numberOfColumns = 2 , parent = 'master_Scrpt_Ldr_Win_ColsHeader' ) cmds.button( 'Script_Loader_WinUI_Btn_Icon' , label = '#' , ann = 'Icon or Text only mode button.' , width = ( Scrpt_Ldr_Win_W_H[0] / 10 ) , parent = 'master_Scrpt_Ldr_Win_ColsHeader_Right' , command = 'Script_Loader_WinUI_IconText()' ) cmds.button( 'Script_Loader_WinUI_Btn_Dock' , label = '~' , ann = 'Docking / UnDocking button.' , width = ( Scrpt_Ldr_Win_W_H[0] / 10 ) , parent = 'master_Scrpt_Ldr_Win_ColsHeader_Right' , command = 'Script_Loader_WinUI_Docker()' ) #opts Scrpt_Ldr_SettingsUI = cmds.button( label = Scrpt_Ldr_Local_FolderPath[0:15] , ann = Scrpt_Ldr_Local_FolderPath , parent = 'master_Scrpt_Ldr_Win_ColsHeader_Left' , command = 'Script_Loader_LocalPathUpdate()') ## main header done, all scripts go below! Scrpt_Ldr_ScrollUI = cmds.scrollLayout( parent = Scrpt_Ldr_PaneAttachUI , cr = True , vst = 10 ) #all script catogories nested to this print Scrpt_Ldr_ScrollUI cmds.showWindow( Scrpt_Ldr_WinUI ) def Script_Loader_StartUI(): Script_Loader_WinUI() Script_Loader_Refresh() def Script_Loader_LocalPathUpdate(): #edits the path button global Scrpt_Ldr_Local_FolderPath global Scrpt_Ldr_SettingsUI tmp = cmds.fileDialog2( dir = Scrpt_Ldr_Local_FolderPath , dialogStyle = 1 , fm = 3 ) if tmp == 'Choose Folder': pass else: cmds.button( Scrpt_Ldr_SettingsUI , parent = 'master_Scrpt_Ldr_Win_ColsHeader_Left' , edit = True , label = tmp[0][0:15] , width = ( Scrpt_Ldr_Win_W_H[0] / 2 ) , ann = tmp[0] ) Scrpt_Ldr_Local_FolderPath = tmp[0] print ( 'User chosen Path: \n' + Scrpt_Ldr_Local_FolderPath + '\n' ) Script_Loader_Refresh() def Script_Loader_WinUI_Docker(): global Scrpt_Ldr_Docked global Scrpt_Ldr_DockUI global Scrpt_Ldr_WinUI if Scrpt_Ldr_Docked is True: # UnDock: cmds.deleteUI( Scrpt_Ldr_DockUI ) Script_Loader_WinUI() Scrpt_Ldr_Docked = False else: # Dock print 'docking' Scrpt_Ldr_Docked = True Scrpt_Ldr_DockUI = cmds.dockControl( fl = False , epo = False , r = False , area = 'left', aa = 'all' , content = Scrpt_Ldr_WinUI ) cmds.button( 'Script_Loader_WinUI_Btn_Dock' , edit = True , label = '||' ) Script_Loader_WinUI_Populate_Fldrs() def Script_Loader_WinUI_IconText(): global Scrpt_Ldr_IconUI if Scrpt_Ldr_IconUI is True: # Make Text Only : Scrpt_Ldr_IconUI = False cmds.button( 'Script_Loader_WinUI_Btn_Icon' , edit = True , label = '#' ) else: # Make Icon only : Scrpt_Ldr_IconUI = True cmds.button( 'Script_Loader_WinUI_Btn_Icon' , edit = True , label = '=' ) Script_Loader_WinUI_Populate_Fldrs() def Script_Loader_Refresh(): global Scrpt_Ldr_Local_FolderPath if Scrpt_Ldr_Local_FolderPath == 'Choose Folder': print 'Please choose a folder filled with Maya scripts to load..' else: print 'Manually Reloading all scripts found and re-populating ScriptLoader.' if Scrpt_Ldr_Local_FolderPath == 'C:': pass else: Script_Loader_Fldrs_Files() Script_Loader_WinUI_Populate_Fldrs() def Script_Loader_Fldrs_Files(): #Point it in a general folder, it will feed back a list of folders + files.. global Results_Folders global Results_Folders_Full global Results_Files global Results_Files_Full global Results_Files_Full_Full global Scrpt_Ldr_Local_FolderPath tmpPath_Split = Scrpt_Ldr_Local_FolderPath.split( '\\' ) os_NicePath = posixpath.join( *tmpPath_Split ) # using the Unix style pathing that's what Maya uses, even on windows.. testNetwork = Scrpt_Ldr_Local_FolderPath.startswith('\\') if testNetwork is True: Additional = ( '//' ) # adding network prefix.. else: Additional = '' os_NicePath = ( Additional + os_NicePath ) print ( 'Printing Nice OS Path: \n ' + os_NicePath + '\n' ) Results_Folders_Full =[ os_NicePath ] Results_Folders =['|:'] Results_Files_Full =[] Results_Files =[] Results_Files_Full_Full = [] print 'Finding all folders..\n' tmp_Results_Folders = [d for d in os.listdir( os_NicePath ) if os.path.isdir(os.path.join( os_NicePath , d ) ) ] for x in tmp_Results_Folders: # finding all folders in location provided. Results_Folders_Full.append( ( os_NicePath + '/' + x ) ) Results_Folders.append( x ) Results_Files = list( Results_Folders ) # this is done to setup the list with the right amount of items. Results_Files_Full = list( Results_Folders ) for i in range( 0 , len( Results_Folders_Full ) ): current = Results_Folders_Full[i] All_Files_In_Current = [] All_FilesFull_In_Current = [] for file in os.listdir( current ): current_FilePath_Full = ( current + '/' + file ) FileTest = os.path.isfile( current_FilePath_Full ) if FileTest is True: All_Files_In_Current.append( file ) All_FilesFull_In_Current.append( current_FilePath_Full ) Results_Files_Full_Full.append( current_FilePath_Full ) Results_Files[i] = All_Files_In_Current Results_Files_Full[i] = All_FilesFull_In_Current def Script_Loader_MakeNice( nameString , columns ): # given a string, will return a version that should just fit the current window layout global Scrpt_Ldr_WinUI toRemove = ['.py' , '.mel' , '.icon' , '.png' , '.jpg' ] tmp = nameString for x in toRemove: tmp = tmp.replace( x , '' ) current_WindowWidth = cmds.window( Scrpt_Ldr_WinUI , w = True , query = True ) # grab current width of control to judge character limit. character_WindowLength = 4 # amount of pixels a character takes avg. frameLayoutIcon = 15 ; scrollBarLayoutIcon = 6 # size in characters, avg. charMaxLength = ( ( ( current_WindowWidth ) / character_WindowLength) - ( frameLayoutIcon + scrollBarLayoutIcon ) ) # area to play with after removing scrollbars width, icons from windows total width. if charMaxLength < len( tmp ): newCleanName = ( tmp[0: ( charMaxLength -3 )] + '..' ) else: newCleanName = tmp[0:int(charMaxLength)] if columns > 1: newCleanName = newCleanName[0:( int( charMaxLength * .9) / columns )] return newCleanName def Script_Loader_findIcon( scriptName ): global Results_Folders global Results_Folders_Full global Results_Files global Results_Files_Full global Results_Files_Full_Full if '.' in scriptName: tmp = scriptName.split('.') end = tmp[0] else: end = scriptName for i in Results_Files_Full_Full: for imageType in Script_Ldr_IconTypes: test = i.lower() if test.endswith( ( end + "." + imageType ).lower() ): result = i return i def Script_Loader_btn_Colour( script_FullList , number ): # given a list of files/scripts, and a number feeds back a colour array.. colour[x ,x ,x] sl_bgc = list( Script_Ldr_ScriptCol ) if '.mel' in script_FullList[number]: sl_ScriptType = Script_Ldr_ScriptColAll[0] else: sl_ScriptType = Script_Ldr_ScriptColAll[1] if number%2==0: divisable = .95 else: divisable = .8 for i in range( 0 , len(sl_bgc) ): sl_bgc[i] = ( ( sl_bgc[i] + sl_ScriptType[i] ) * divisable ) return sl_bgc def Script_Loader_btn_cols( current_FileN_Set ): # given a list, gives back column amount. if len( current_FileN_Set ) > 1: cols = 2 if len( current_FileN_Set ) > 2: cols = 3 if len( current_FileN_Set ) > 3: cols = 4 else: cols = 1 return cols def Script_Loader_btn_command( script_path ): # given a location will feed back the command string to use to initialise. testNetwork = script_path.startswith('\\') if testNetwork is True: Additional = ( '//' ) # adding network prefix.. else: Additional = '' tmp = script_path.split( '\\' ) tmp2 = posixpath.join( *tmp ) # using the Unix style pathing that's what Maya uses, even on windows.. Command_String = '' if '.mel' in script_path: Command_String = ('mel.eval(\'source \"' + Additional + tmp2 + '\" ;\')' ) else: Command_String = ('execfile( (\'' + Additional + tmp2 + '\'))' ) return Command_String def Script_Loader_WinUI_Populate_Fldrs(): global Scrpt_Ldr_IconUI global Results_Folders global Results_Folders_Full global Results_Files global Results_Files_Full global Scrpt_Ldr_WinUI global Scrpt_Ldr_ScrollUI global Scrpt_Ldr_PaneAttachUI cmds.deleteUI( Scrpt_Ldr_ScrollUI ) Scrpt_Ldr_ScrollUI = cmds.scrollLayout( parent = Scrpt_Ldr_PaneAttachUI , cr = True , vst = 10 ) #all script catogories nested to this Script_Ldr_IgnoreTypes = [] Script_Ldr_IgnoreTypes.extend( Script_Ldr_IconTypes ) Script_Ldr_IgnoreTypes.extend( Script_Ldr_FileTypes ) Script_Ldr_IgnoreTypes_set = set( Script_Ldr_IgnoreTypes ) frameLayouts_Made = [] # UI elements to parent to if Scrpt_Ldr_IconUI is False: for i in range( 0 , len( Results_Folders ) ): # this creates the folder frames, not populated. tmp_Name = ( '_btn_frameUI' + str(i) ) tmp = cmds.frameLayout( label = str( Results_Folders[i] ) , cll = True , cl = True , parent = Scrpt_Ldr_ScrollUI ) cmds.columnLayout( tmp_Name , adj=True) frameLayouts_Made.append( tmp_Name ) for i in range( 0 , len( Results_Folders ) ): # for all the folders found.. populates with btns.. current_Parent = frameLayouts_Made[i] current_FileN_Set = Results_Files[i] current_FileFull_Set = Results_Files_Full[i] count = 0 for BtnName in current_FileN_Set: tmpCommand = Script_Loader_btn_command( current_FileFull_Set[count]) buttonType = BtnName.split('.') if buttonType[1].lower() in Script_Ldr_IgnoreTypes_set: print ( 'ignored type ' + BtnName ) else: cmds.iconTextButton( style = 'textOnly' , bgc = ( Script_Loader_btn_Colour( current_FileN_Set , count ) ), label = Script_Loader_MakeNice( BtnName , 1 ) , align = 'left' , parent = current_Parent , command = tmpCommand ) count+=1 else: for i in range( 0 , len( Results_Folders ) ): # this creates the folder frames, not populated. tmp_Name = ( '_btn_frameUI' + str(i) ) tmp = cmds.frameLayout( label = str( Results_Folders[i] ) , cll = True , cl = True , parent = Scrpt_Ldr_ScrollUI ) current_FileN_Set = Results_Files[i] cmds.rowColumnLayout( tmp_Name , numberOfColumns = Script_Loader_btn_cols( current_FileN_Set ) ) frameLayouts_Made.append( tmp_Name ) for i in range( 0 , len( Results_Folders ) ): # for all the folders found.. populates with btns.. current_Parent = frameLayouts_Made[i] current_FileN_Set = Results_Files[i] current_FileFull_Set = Results_Files_Full[i] columns = Script_Loader_btn_cols( current_FileN_Set ) count = 0 for BtnName in current_FileN_Set: pass ## need to find a way to remove everything but mel and py and txt from the all list. buttonType = BtnName.split('.') if buttonType[1].lower() in Script_Ldr_IgnoreTypes_set: print ( 'ignored type ' + BtnName ) else: current_WindowWidth = cmds.window( Scrpt_Ldr_WinUI , w = True , query = True ) # grab current width of control to judge character limit. tmpName = Script_Loader_MakeNice( BtnName , columns ) tmpImage = Script_Loader_findIcon( current_FileN_Set[count] ) tmpCommand = Script_Loader_btn_command( current_FileFull_Set[count]) if tmpImage is None: cmds.iconTextButton( style = 'textOnly' , bgc = ( Script_Loader_btn_Colour( current_FileFull_Set , count ) ), label = tmpName , width = ( (current_WindowWidth - 20) / Script_Loader_btn_cols( current_FileFull_Set ) ) , align = 'left' , parent = current_Parent , ann = BtnName , command = tmpCommand ) else: cmds.iconTextButton( style = 'iconOnly' , image1 = tmpImage , bgc = ( Script_Loader_btn_Colour( current_FileFull_Set , count ) ) , align = 'left' , parent = current_Parent , ann = BtnName , command = tmpCommand ) count+=1 Script_Loader_StartUI()