def get_or_create_shotgun_menu(menu_name): app = NatronGui.natron.getActiveInstance() app_id = app.getAppID() app_gui = NatronGui.natron.getGuiInstance(app_id) fake_panel = NatronGui.PyPanel("shotgun.software.engine", "tk-natron", True, app_gui) main_window = fake_panel.parent() del fake_panel menu_bar = None for m in main_window.findChildren(QtGui.QMenuBar): menu_bar = m break for action in menu_bar.actions(): if action.text() == menu_name: return action.menu() help_action = None for action in menu_bar.actions(): if action.text() == "Help": shotgun_menu = QtGui.QMenu(menu_name) menu_bar.insertMenu(action, shotgun_menu) return shotgun_menu return None
def add_command_to_menu(self, menu): """ Adds an app command to the menu """ # create menu sub-tree if need to: # Support menu items seperated by '/' parent_menu = menu parts = self.name.split("/") for item_label in parts[:-1]: # see if there is already a sub-menu item sub_menu = self._find_sub_menu_item(parent_menu, item_label) if sub_menu: # already have sub menu parent_menu = sub_menu else: new_sub_menu = QtGui.QMenu(item_label) parent_menu.addMenu(new_sub_menu) parent_menu = new_sub_menu # finally create the command menu item: menu_action = parent_menu.addAction(parts[-1]) #menu_action.triggered.connect(self.callback) menu_action.triggered.connect(lambda: menu_callback(self.callback)) if "tooltip" in self.properties: menu_action.setToolTip(self.properties["tooltip"]) if "enable_callback" in self.properties: menu_action.setEnabled(self.properties["enable_callback"]())
def _add_app_menu(self, commands_by_app): """ Add all apps to the main menu, process them one by one. """ for app_name in sorted(commands_by_app.keys()): if len(commands_by_app[app_name]) > 1: # more than one menu entry fort his app # make a sub menu and put all items in the sub menu app_menu = QtGui.QMenu(app_name) self._menu_handle.addMenu(app_menu) # get the list of menu cmds for this app cmds = commands_by_app[app_name] # make sure it is in alphabetical order cmds.sort(key=lambda x: x.name) for cmd in cmds: cmd.add_command_to_menu(app_menu) else: # this app only has a single entry. # display that on the menu # todo: Should this be labelled with the name of the app # or the name of the menu item? Not sure. cmd_obj = commands_by_app[app_name][0] if not cmd_obj.favourite: # skip favourites since they are alreay on the menu cmd_obj.add_command_to_menu(self._menu_handle)
def __init__(self, engine, menu_name): self._engine = engine self._menu_name = menu_name self._dialogs = [] self._widget = QtGui.QWidget() self._handle = QtGui.QMenu(self._menu_name, self._widget) self._ui_cache = [] self.logger = self._engine.logger
def get_or_create_shotgun_menu(menu_name): """ Creates or retrieves the Shotgun Menu entry in the Menu bar. """ menu_bar = get_menubar() if menu_bar: for action in menu_bar.actions(): if action.text().replace("&", "") == menu_name: return action.menu() for action in menu_bar.actions(): if action.text().replace("&", "") == "Help": shotgun_menu = QtGui.QMenu(menu_name, menu_bar) menu_bar.insertMenu(action, shotgun_menu) return shotgun_menu
def __init__(self, parent): """ Constructor """ QtGui.QWidget.__init__(self, parent) # make sure this widget isn't shown self.setVisible(False) # set up the UI self.ui = Ui_ListWidget() self.ui.setupUi(self) # set up action menu self._menu = QtGui.QMenu() self._actions = [] self.ui.button.setMenu(self._menu) self.ui.button.setVisible(False)
def clear_app_uis(self): # empty the project commands self._project_command_model.clear() # hide the pipeline configuration bar self.ui.configuration_frame.hide() # hide the setup project ui if it is shown self.setup_project_widget.hide() self.update_project_config_widget.hide() self.setup_new_os_widget.hide() # clear the project specific menu self.project_menu = QtGui.QMenu(self) self.project_menu.triggered.connect(self._on_project_menu_triggered) self.project_menu.addAction(self.ui.actionProject_Filesystem_Folder) self.ui.project_menu.setMenu(self.project_menu) self.__pipeline_configuration_separator = None
def _add_context_menu(self): """ Adds a context menu which displays the current context """ ctx = self._engine.context ctx_name = str(ctx) # # create the menu object ctx_menu = QtGui.QMenu(ctx_name) self._menu_handle.addMenu(ctx_menu) action_reload = ctx_menu.addAction("Reload Shotgun", self._reload_sg) action_reload = ctx_menu.addAction("Jump to Shotgun", self._jump_to_sg) action_reload = ctx_menu.addAction("Jump to File System", self._jump_to_fs) ctx_menu.addSeparator() return ctx_menu
def reset(self): """ Clears the project specific related QT menu and add basic menu actions and pipeline configuration section divider. """ if self._project_menu: self._pipeline_configuration_separator = None self._project_menu.clear() self._project_menu = QtGui.QMenu(self._parent) self._project_menu.aboutToShow.connect( self._on_project_menu_about_to_show) self._project_menu.triggered.connect(self._on_project_menu_triggered) self._parent.ui.actionProject_Filesystem_Folder.setVisible(True) self._project_menu.addAction( self._parent.ui.actionProject_Filesystem_Folder) self._parent.ui.project_menu.setMenu(self._project_menu) # Add a section separator that will be above the pipeline configurations. # The context menu actions will be inserted above this saparator. self._pipeline_configuration_separator = self._project_menu.addSeparator( )
def __init__(self, parent): """ Constructor """ QtGui.QWidget.__init__(self, parent) # make sure this widget isn't shown self.setVisible(False) # set up the UI self.ui = Ui_ThumbWidget() self.ui.setupUi(self) # set up an event filter to ensure that the thumbnails # are scaled in a square fashion. filter = ResizeEventFilter(self.ui.thumbnail) filter.resized.connect(self.__on_thumb_resized) self.ui.thumbnail.installEventFilter(filter) # set up action menu self._menu = QtGui.QMenu() self._actions = [] self.ui.button.setMenu(self._menu) self.ui.button.setVisible(False)
def get_or_create_shotgun_menu(menu_name): """ Creates or retrieves the Shotgun Menu entry in the Menu bar. """ ctx = sd.getContext() app = ctx.getSDApplication() uiMgr = app.getQtForPythonUIMgr() menu_id = "Pfx.Editor.Menu.%s" % menu_name menu = uiMgr.findMenuFromObjectName(menu_id) if not menu: help_menu = uiMgr.findMenuFromObjectName("Pfx.Editor.Menu.Help") main_window = uiMgr.getMainWindow() menu_bar = main_window.menuBar() menu = QtGui.QMenu(menu_name, menu_bar) menu.setObjectName(menu_id) if help_menu: menu_bar.insertMenu(help_menu.menuAction(), menu) else: menu_bar.addMenu(menu) return menu
def _add_sub_menu(self, menu_name, parent_menu): sub_menu = QtGui.QMenu(title=menu_name, parent=parent_menu) parent_menu.addMenu(sub_menu) return sub_menu
def _create_hiero_menu(self, add_commands=True, commands=None): """ Creates the "Shotgun" menu in Hiero. :param bool add_commands: If True, menu commands will be added to the newly-created menu. If False, the menu will be created, but no contents will be added. Defaults to True. :param dict commands: The engine commands to add to the various menus. The dictionary is structured the same as engine.commands is, where the key is the name of the command, and the value is a dictionary of command properties. """ import hiero if self._menu_handle is not None: self.destroy_menu() from sgtk.platform.qt import QtGui self._menu_handle = QtGui.QMenu("Shotgun") help = hiero.ui.findMenuAction("Cache") menuBar = hiero.ui.menuBar() menuBar.insertMenu(help, self._menu_handle) self._menu_handle.clear() # If we were asked not to add any commands to the menu, # then bail out. if not add_commands: return # Now add the context item on top of the main menu. self._context_menu = self._add_context_menu() self._menu_handle.addSeparator() if not commands: return # Now enumerate all items and create menu objects for them. menu_items = [] for (cmd_name, cmd_details) in commands.items(): menu_items.append( HieroAppCommand(self.engine, cmd_name, cmd_details)) # Now add favourites. for fav in self.engine.get_setting("menu_favourites"): app_instance_name = fav["app_instance"] menu_name = fav["name"] # Scan through all menu items. for cmd in menu_items: if cmd.app_instance_name == app_instance_name and cmd.name == menu_name: # Found our match! cmd.add_command_to_menu(self._menu_handle) # Mark as a favourite item. cmd.favourite = True # Get the apps for the various context menus. self._context_menus_to_apps = { "bin_context_menu": [], "timeline_context_menu": [], "spreadsheet_context_menu": [], } remove = set() for (key, apps) in self._context_menus_to_apps.iteritems(): items = self.engine.get_setting(key) for item in items: app_instance_name = item["app_instance"] menu_name = item["name"] # Scan through all menu items. for (i, cmd) in enumerate(menu_items): if (cmd.app_instance_name == app_instance_name and cmd.name == menu_name): # Found the match. apps.append(cmd) cmd.requires_selection = item["requires_selection"] if not item["keep_in_menu"]: remove.add(i) break for index in sorted(remove, reverse=True): del menu_items[index] # Register for the interesting events. hiero.core.events.registerInterest( "kShowContextMenu/kBin", self.eventHandler, ) hiero.core.events.registerInterest( "kShowContextMenu/kTimeline", self.eventHandler, ) # Note that the kViewer works differently than the other things # (returns a hiero.ui.Viewer object: http://docs.thefoundry.co.uk/hiero/10/hieropythondevguide/api/api_ui.html#hiero.ui.Viewer) # so we cannot support this easily using the same principles as for the other things. hiero.core.events.registerInterest( "kShowContextMenu/kSpreadsheet", self.eventHandler, ) self._menu_handle.addSeparator() # Now go through all of the menu items. # Separate them out into various sections. commands_by_app = {} for cmd in menu_items: if cmd.type == "context_menu": cmd.add_command_to_menu(self._context_menu) else: # Normal menu. app_name = cmd.app_name if app_name is None: # Unparented app. app_name = "Other Items" if not app_name in commands_by_app: commands_by_app[app_name] = [] commands_by_app[app_name].append(cmd) # Now add all apps to main menu. self._add_app_menu(commands_by_app)
def __init__(self, app): """ main UI for the Maya Create Ocean options """ QtGui.QWidget.__init__(self) self.app = app tk = sgtk.sgtk_from_path("T:/software/bubblebathbay") self.editor = self._getEditor() ## To get the step context = self.app.context debug(self.app, method = 'run_app', message = 'Context Step: %s' % context.step['name'], verbose = False) if context.step['name'] == 'FX' or context.step['name'] == 'Additional FX': self.editor = 'modelPanel4' if self.editor: debug(self.app, method = 'Main_UI', message = 'Lauching UI', verbose = False) ## Setup the paths for the presets and defaults etc... scene_path = os.path.abspath(cmds.file(query=True, sn= True)) debug(self.app, method = 'Main_UI', message = 'scene_path: %s' % scene_path, verbose = False) epName = scene_path.split('\\')[3] ###NOTE NO UNDERSCORES ARE ALLOWED HERE OR THE F*****G THING FAILS MISERABLY!!! FOR ***HOURS*** OF YOUR PRECIOUS LIFE!! wakePreset = 'newOceanWakeTexture' foamPreset = 'newOceanWakeFoamTexture' oceanDefaultPreset = 'oceanDefaultPreset' wakeEmitterPreset = 'wakeEmitter.mel' foamEmitterPreset = 'foamEmitter.mel' hullEmitterPreset = 'hullEmitter.mel' ## Now work out the published animation fx folder to get the ocean preset from for the published animation so our maya ocean matches after rebuild. entity = self.app.context.entity debug(self.app, method = 'Main_UI', message = 'entity: %s' % entity, verbose = False) debug(self.app, method = 'Main_UI', message = 'context.step["name"]: %s' % context.step['name'], verbose = False) ## Now get the templates from the shot_step.yml ## ocean_preset_template: maya_shot_oceanPresets ## ocean_publish_template: maya_shot_publishOceanCache oceanPublishTemplate = self.app.get_template('ocean_publish_template') ## maya_shot_oceanPresets: '@presetsRoot/ocean/{presetName}.mel' oceanWakePresetTemplate = self.app.get_template('ocean_preset_template') oceanFoamPresetTemplate = self.app.get_template('ocean_preset_template') oceanDefaultPresetTemplate = self.app.get_template('ocean_preset_template') animOceanPublishedPresetTemplate = self.app.get_template('shotfx_publish_template') ## maya_shot_publishOceanCache: '@shot_root/publish/fluids/{name}.v{version}.abc' debug(self.app, method = 'Main_UI', message = 'ocean_publish_template: %s' % oceanPublishTemplate, verbose = False) debug(self.app, method = 'Main_UI', message = 'oceanWakePresetTemplate: %s' % oceanWakePresetTemplate, verbose = False) debug(self.app, method = 'Main_UI', message = 'oceanFoamPresetTemplate: %s' % oceanFoamPresetTemplate, verbose = False) debug(self.app, method = 'Main_UI', message = 'oceanDefaultPresetTemplate: %s' % oceanDefaultPresetTemplate, verbose = False) debug(self.app, method = 'Main_UI', message = 'animOceanPublishedPresetTemplate: %s' % animOceanPublishedPresetTemplate, verbose = False) print ## Now get ready to convert these to / pathing using the r approach ## CONVERT WAKE TO A PROPER PATH self.wakePresetPath = r'%s' % oceanWakePresetTemplate.apply_fields({'presetName' : wakePreset}) debug(self.app, method = 'Main_UI', message = 'self.wakePresetPath: %s' % self.wakePresetPath.replace('\\', '/'), verbose = False) ## CONVERT FOAM TO A PROPER PATH self.foamPresetPath = r'%s' % oceanFoamPresetTemplate.apply_fields({'presetName' : foamPreset}) debug(self.app, method = 'Main_UI', message = 'self.foamPresetPath: %s' % self.foamPresetPath.replace('\\', '/'), verbose = False) ############################################################## ################ Process ocean preset path for Anim or FX step | Animation will use default preset, FX will use published preset. ############################################################## isFX = False if cmds.objExists('fxNugget'): debug(self.app, method = 'Main_UI', message = 'fxNugget found...', verbose = False) # getAnimVersionFolders = tk.paths_from_template(animOceanPublishedPresetTemplate, {'id' : entity["id"], 'Shot' : entity["name"]}) getAnimVersionFolders = tk.paths_from_template(animOceanPublishedPresetTemplate, {'Step' : 'Anm', 'id' : entity["id"], 'Shot' : entity["name"]}) debug(self.app, method = 'Main_UI', message = 'getAnimVersionFolders: %s' % getAnimVersionFolders, verbose = False) highestAnimVerFolder = max(getAnimVersionFolders) debug(self.app, method = 'Main_UI', message = 'Path to highest oceanPreset AnimVerFolder: %s' % highestAnimVerFolder, verbose = False) if not highestAnimVerFolder: cmds.warning('THERE IS NO PUBLISHED OCEAN PRESET FROM ANIMAITON! PLEASE FIX THIS NOW!') isFX = True else: cmds.warning('NO FX NUGGET FOUND!') getAnimVersNum = None isFX = False ############################################################## ################ Now set the preset path properly ############################################################## self.oceanPublishedPresetPath = None debug(self.app, method = 'Main_UI', message = 'Figuring out the ocean preset path now...', verbose = False) debug(self.app, method = 'Main_UI', message = 'isFX: %s' % isFX, verbose = False) if context.step['name'] == 'Anm' or context.step['name'] == 'FX' or context.step['name'] == 'Additional FX' or context.step['name'] == 'Blocking': if isFX: getMelPreset = [eachMel for eachMel in os.listdir(highestAnimVerFolder) if eachMel.endswith('.mel')] debug(self.app, method = 'Main_UI', message = 'getMelPreset: %s' % getMelPreset, verbose = False) if not getMelPreset: cmds.warning('NO ANIMATION OCEAN PRESET FOUND, USING THE DEFAULT.') debug(self.app, method = 'Main_UI', message = 'No published animation ocean preset found!!! Using default! NOT GOOD!', verbose = False) self.oceanPublishedPresetPath = r'%s' % oceanDefaultPresetTemplate.apply_fields({'presetName' : oceanDefaultPreset}) debug(self.app, method = 'Main_UI', message = 'self.oceanPublishedPresetPath: %s' % self.oceanPublishedPresetPath, verbose = False) else: presetPath = r'%s\%s' % (highestAnimVerFolder, getMelPreset[0]) debug(self.app, method = 'Main_UI', message = 'Using published ocean preset: %s' % presetPath, verbose = False) self.oceanPublishedPresetPath = presetPath debug(self.app, method = 'Main_UI', message = 'self.oceanPublishedPresetPath: %s' % self.oceanPublishedPresetPath, verbose = False) else: debug(self.app, method = 'Main_UI', message = 'No getAnimVersionFolders found... must be an animation scene or blocking scene setting default ocean preset template now', verbose = False) self.oceanPublishedPresetPath = r'%s' % oceanDefaultPresetTemplate.apply_fields({'presetName' : oceanDefaultPreset}) debug(self.app, method = 'Main_UI', message = 'self.oceanPublishedPresetPath: %s' % self.oceanPublishedPresetPath, verbose = False) else: debug(self.app, method = 'Main_UI', message = 'Context step is %s.' % context.step['name'], verbose = False) self.oceanPublishedPresetPath = r'%s' % oceanDefaultPresetTemplate.apply_fields({'presetName' : oceanDefaultPreset}) debug(self.app, method = 'Main_UI', message = 'self.oceanPublishedPresetPath: %s' % self.oceanPublishedPresetPath, verbose = False) ## Now build the UI self.mainLayout = QtGui.QVBoxLayout(self) ## High and Low Tide layout self.lowhiLayout = QtGui.QHBoxLayout(self) self.highTide = QtGui.QRadioButton('High Tide') self.highTide.setChecked(True) self.highTide.setEnabled(False) self.highTide.hide() self.lowTide = QtGui.QRadioButton('Low Tide') self.lowTide.setChecked(False) self.lowTide.setEnabled(False) self.lowTide.hide() ## Now parent these tot the layout self.lowhiLayout.addWidget(self.highTide) self.lowhiLayout.addWidget(self.lowTide) self.lowhiLayout.addStretch(1) debug(self.app, method = 'Main_UI', message = 'lowhiLayout built successfully...', verbose = False) ## Animation ocean setup self.animGroupBox = QtGui.QGroupBox(self) self.animGroupBox.setTitle('Animation Ocean Setup:') debug(self.app, method = 'Main_UI', message = 'animGroupBox built successfully...', verbose = False) self.animLayout = QtGui.QVBoxLayout(self.animGroupBox) debug(self.app, method = 'Main_UI', message = 'animLayout built successfully...', verbose = False) ## Build Base Animation Ocean Setup Button self.buildOceanButton = QtGui.QPushButton('Setup Animation Ocean') self.buildOceanButton.setStyleSheet("QPushButton {text-align: center; background: dark green; color: white}") self.buildOceanButton.pressed.connect(partial(oceanBuilder.buildAnimOcean, self.editor, self.oceanPublishedPresetPath, self.foamPresetPath.replace('\\', '/'), self.wakePresetPath.replace('\\', '/'), self.highTide.isChecked())) debug(self.app, method = 'Main_UI', message = 'self.buildOceanButton connected..', verbose = False) ## Fetch FX Cache for interactive wake referencing self.fetchWakeFromFXButton = QtGui.QPushButton('Fetch Cache from FX') self.fetchWakeFromFXButton.setStyleSheet("QPushButton {text-align: center; background: dark orange; color: black}") self.fetchWakeFromFXButton.pressed.connect(self.get_shotfx_publish_dirs) debug(self.app, method = 'Main_UI', message = 'self.fetchWakeFromFXButton connected..', verbose = False) # ## Setup Interactive Ocean On Selected world_ctrl button # self.buildInteractiveOceanButton = QtGui.QPushButton('Setup Interactive Ocean On Sel world_ctrl') # self.buildInteractiveOceanButton.pressed.connect(self.setupInteractionOcean) # self.buildInteractiveOceanButton.setEnabled(False) # debug(self.app, method = 'Main_UI', message = 'self.buildInteractiveOceanButton connected..', verbose = False) # # ## Apply Fluid Emitter Presets button # self.buildInteractivePresetsButton = QtGui.QPushButton('Apply Fluid Emitter Presets') # self.buildInteractivePresetsButton.pressed.connect(partial(fluidLib._setFluidEmitterPresets, wakeEmitterPreset, foamEmitterPreset, hullEmitterPreset)) # self.buildInteractivePresetsButton.setEnabled(False) # debug(self.app, method = 'Main_UI', message = 'self.buildInteractivePresetsButton connected..', verbose = False) self.animLayout.addWidget(self.buildOceanButton) self.animLayout.addWidget(self.fetchWakeFromFXButton) # self.animLayout.addWidget(self.buildInteractiveOceanButton) # self.animLayout.addWidget(self.buildInteractivePresetsButton) debug(self.app, method = 'Main_UI', message = 'animLayout built successfully...', verbose = False) ###################################### ##### FX STUFF if context.step['name'] == 'FX' or context.step['name'] == 'Additional FX': ############################### ## BUILD THE MAIN BUILD BUTTONS ############################### self.FXBuildGroupBox = QtGui.QGroupBox(self) self.FXBuildGroupBox.setTitle('FX Build Stuff:') self.mainFXBuildLayout = QtGui.QVBoxLayout(self.FXBuildGroupBox) self.hLayout = QtGui.QHBoxLayout(self) self.buildFXOceanSetupButton = QtGui.QPushButton('1. Setup FX Ocean') self.buildFXOceanSetupButton.pressed.connect(partial(self.setupFXOcean, highestAnimVerFolder)) self.buildFXOceanSetupButton.setStyleSheet("QPushButton {text-align: center; background: dark green}") self.buildPresetsButton = QtGui.QPushButton('2. Apply All Fluid Emitter Presets') self.buildPresetsButton.pressed.connect(partial(fluidLib._setFluidEmitterPresets, wakeEmitterPreset, foamEmitterPreset, hullEmitterPreset)) self.buildPresetsButton.setStyleSheet("QPushButton {text-align: center; background: dark green}") # self.buildParticlesPresetsButton = QtGui.QPushButton('3. Apply All Particle Presets') # self.buildParticlesPresetsButton.pressed.connect(self._setPresets) # self.buildParticlesPresetsButton.setStyleSheet("QPushButton {text-align: center; background: dark green}") ## Add the buttons to the hLayout self.hLayout.addWidget(self.buildFXOceanSetupButton) self.hLayout.addWidget(self.buildPresetsButton) # self.hLayout.addWidget(self.buildParticlesPresetsButton) debug(self.app, method = 'Main_UI', message = 'Added widgets to hLayout', verbose = False) self.mainFXBuildLayout.addLayout(self.hLayout) ############################### ## BUILD THE MAIN VIEW SWITCHING BUTTONS ############################### self.FXViewGroupBox = QtGui.QGroupBox(self) self.FXViewGroupBox.setTitle('Change FX Scene Settings:') self.mainFXViewLayout = QtGui.QVBoxLayout(self.FXViewGroupBox) self.h2Layout = QtGui.QHBoxLayout(self) self._setForRenderButton = QtGui.QPushButton('Apply Render View Settings') self._setForRenderButton.pressed.connect(partial(self._setForRender)) self._setForRenderButton.setStyleSheet("QPushButton {text-align: center; background: dark grey}") self._setForFluidsButton = QtGui.QPushButton('Apply Fluid View Settings') self._setForFluidsButton.pressed.connect(partial(self._setForFluids)) self._setForFluidsButton.setStyleSheet("QPushButton {text-align: center; background: dark grey}") # self._fetchAnimAlembicButton = QtGui.QPushButton(Icon('alembic.png'), 'Fetch Alembic Anim Caches', self) # self._fetchAnimAlembicButton.pressed.connect(partial(self._fetchAlembicCaches, highestAnimVerFolder)) # self._fetchAnimAlembicButton.setStyleSheet("QPushButton {text-align: center; background: dark grey}") ## Add the buttons to the h2Layout self.h2Layout.addWidget(self._setForRenderButton) self.h2Layout.addWidget(self._setForFluidsButton) # self.h2Layout.addWidget(self._fetchAnimAlembicButton) debug(self.app, method = 'Main_UI', message = 'Added widgets to h2Layout', verbose = False) self.mainFXViewLayout.addLayout(self.h2Layout) ############################## ##### MAIN SETTINGS UI ############################## self.FXSettingsGroupBox = QtGui.QGroupBox(self) self.FXSettingsGroupBox.setTitle('FX Build Settings:') self.mainFXLayout = QtGui.QVBoxLayout(self.FXSettingsGroupBox) self.optionsVBoxLayout = QtGui.QVBoxLayout(self) self.nurbsPreviewOptionsLayout = QtGui.QHBoxLayout() ##xRes of the NURBSPlane self.xResLabel = QtGui.QLabel('zRes') self.xRes = QtGui.QDoubleSpinBox() self.xRes.setRange(0, 100) self.xRes.setSingleStep(1) self.xRes.setValue(20) ##zRes of the NURBSPlane self.zResLabel = QtGui.QLabel('zRes') self.zRes = QtGui.QDoubleSpinBox() self.zRes.setRange(0, 100) self.zRes.setSingleStep(1) self.zRes.setValue(20) debug(self.app, method = 'Main_UI', message = 'Nurbs Preview options built...', verbose = False) self.mistPresetLabel = QtGui.QLabel('mist_ParticlePreset') self.mistPreset_pullDownMenu = QtGui.QComboBox (self) self.mistPreset_pullDownMenu.setMinimumWidth(250) self.mistPreset_pullDownMenu.setMaximumHeight(25) self.sprayPresetLabel = QtGui.QLabel('spray_ParticlePreset') self.sprayPreset_pullDownMenu = QtGui.QComboBox (self) self.sprayPreset_pullDownMenu.setMinimumWidth(250) self.sprayPreset_pullDownMenu.setMaximumHeight(25) self.rearPresetLabel = QtGui.QLabel('rear_ParticlePreset') self.rearPreset_pullDownMenu = QtGui.QComboBox (self) self.rearPreset_pullDownMenu.setMinimumWidth(250) self.rearPreset_pullDownMenu.setMaximumHeight(25) ## Add the res to the layout self.nurbsPreviewOptionsLayout.addWidget(self.xResLabel) self.nurbsPreviewOptionsLayout.addWidget(self.xRes) self.nurbsPreviewOptionsLayout.addWidget(self.zResLabel) self.nurbsPreviewOptionsLayout.addWidget(self.zRes) self.nurbsPreviewOptionsLayout.addWidget(self.mistPresetLabel) self.nurbsPreviewOptionsLayout.addWidget(self.mistPreset_pullDownMenu) self.nurbsPreviewOptionsLayout.addWidget(self.sprayPresetLabel) self.nurbsPreviewOptionsLayout.addWidget(self.sprayPreset_pullDownMenu) self.nurbsPreviewOptionsLayout.addWidget(self.rearPresetLabel) self.nurbsPreviewOptionsLayout.addWidget(self.rearPreset_pullDownMenu) self.nurbsPreviewOptionsLayout.addStretch(1) debug(self.app, method = 'Main_UI', message = 'Added widgets to nurbsPreviewOptionsLayout', verbose = False) self.optionsVBoxLayout .addLayout(self.nurbsPreviewOptionsLayout) self.mainFXLayout.addLayout(self.optionsVBoxLayout) debug(self.app, method = 'Main_UI', message = 'FXSettingsGroupBox built successfully...', verbose = False) ################################# ############################## ##### OPTIONS BOX BUILD self.FXOptionsGroupBox = QtGui.QGroupBox(self) self.FXOptionsGroupBox.setTitle('FX Ocean Manual Hookups:') self.FXOptionsMainLayout = QtGui.QVBoxLayout(self.FXOptionsGroupBox) ### MANUAL BUILD BUTTONS self.optionshLayout = QtGui.QHBoxLayout() # self.connectAllWithOceanButton = QtGui.QPushButton('FX / Connect Height Locks To Ocean') # self.connectAllWithOceanButton.pressed.connect(partial(connOH.connectAllWithOceanHeightAttr)) # debug(self.app, method = 'Main_UI', message = 'self.connectAllWithOceanButton built...', verbose = False) ############################################################# self.connectToOceanButton = QtGui.QToolButton(self) self.connectToOceanButton.setPopupMode(QtGui.QToolButton.MenuButtonPopup) self.connectToOceanButton.setStyleSheet("QToolButton {text-align: center; background: rgb(100, 100, 100); color: white}") connectToOceanButtonStretchPolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.connectToOceanButton.setSizePolicy(connectToOceanButtonStretchPolicy) self.connectToOceanButton.setText('All Ocean Hookup') self.connectToOceanButton.setMenu( QtGui.QMenu(self.connectToOceanButton) ) self.connectToOceanButton.clicked.connect(self.connectOceanHeights) self.connectToOceanListWidget = QtGui.QListWidget() self.connectToOceanListWidget.setFixedHeight(60) self.connectToOceanListWidget.addItem('Dock') self.connectToOceanListWidget.addItem('Boat') self.connectToOceanListWidget.addItem('Prop') self.connectToOceanListWidget.addItem('All') self.connectToOceanListWidget.clicked.connect(self.connectToOceanButtonText) self.connectToOceanAction = QtGui.QWidgetAction(self.connectToOceanButton) self.connectToOceanAction.setDefaultWidget(self.connectToOceanListWidget) self.connectToOceanButton.menu().addAction(self.connectToOceanAction) ############################################################# if context.step['name'] == 'FX' or context.step['name'] == 'Additional FX': self.animShaderIntersectButton = QtGui.QPushButton('Anim Intersect') self.animShaderIntersectButton.pressed.connect( partial( fluidLib._intersect_animShader_expression ) ) debug(self.app, method = 'Main_UI', message = 'self.animShaderIntersectButton built...', verbose = False) self.dispShaderIntersectButton = QtGui.QPushButton('Disp Intersect') self.dispShaderIntersectButton.pressed.connect( partial( fluidLib._intersect_dispShader_expression ) ) debug(self.app, method = 'Main_UI', message = 'self.dispShaderIntersectButton built...', verbose = False) self.linkEmittersButton = QtGui.QPushButton('FX / Link Emitters To Ocean') self.linkEmittersButton.pressed.connect(partial(fluidLib._linkWakeEmitters)) debug(self.app, method = 'Main_UI', message = 'self.linkEmittersButton built...', verbose = False) self.optionshLayout.addWidget(self.connectToOceanButton) ## Add the buttons to the optionshLayout if context.step['name'] == 'FX' or context.step['name'] == 'Additional FX': self.optionshLayout.addWidget(self.animShaderIntersectButton) self.optionshLayout.addWidget(self.dispShaderIntersectButton) self.optionshLayout.addWidget(self.linkEmittersButton) ### Now parent the FXOption layouts to the options main VBoxLayout self.FXOptionsMainLayout.addLayout(self.optionshLayout) ############################### ## FX INTERACTIVE SECTION ############################### if context.step['name'] == 'FX' or context.step['name'] == 'Additional FX': ## MAIN SECTION self.FXInteractiveGroupBox = QtGui.QGroupBox(self) self.FXInteractiveGroupBox.setTitle('FX Interactive:') self.FXInteractiveMainLayout = QtGui.QVBoxLayout(self.FXInteractiveGroupBox) ## MAIN LAYOUT self.FXInteractiveLayout = QtGui.QHBoxLayout() ## SETUP BUTTONS self.cacheFluidsButton = QtGui.QPushButton('Cache fluids') self.cacheFluidsButton.pressed.connect(fc.cacheFluidsToCTemp) self.cacheFluidsButton.setStyleSheet("QPushButton {text-align: center; background: dark orange; color: black}") # self.cacheFluidsButton.setEnabled(False) self.previewInteractiveButton = QtGui.QPushButton('Preview Interactive') self.previewInteractiveButton.pressed.connect(fc.previewInteractiveCaches) self.previewInteractiveButton.setStyleSheet("QPushButton {text-align: center; background: dark orange; color: black}") # self.previewInteractiveButton.setEnabled(False) self.cleanupCacheFilesButton = QtGui.QPushButton('Cleanup fluids caches') self.cleanupCacheFilesButton.setStyleSheet("QPushButton {text-align: center; background: dark orange; color: black}") self.cleanupCacheFilesButton.pressed.connect(fc.deleteCaches) # self.cleanupCacheFilesButton.setEnabled(False) self.cleanupICacheFilesButton = QtGui.QPushButton('Cleanup interactive caches') self.cleanupICacheFilesButton.setStyleSheet("QPushButton {text-align: center; background: dark orange; color: black}") self.cleanupICacheFilesButton.pressed.connect(fc.deleteInteractiveCaches) # self.cleanupICacheFilesButton.setEnabled(False) ## ADD BUTTON TO LAYOUT self.FXInteractiveLayout.addWidget(self.cacheFluidsButton) self.FXInteractiveLayout.addWidget(self.previewInteractiveButton) self.FXInteractiveLayout.addWidget(self.cleanupCacheFilesButton) self.FXInteractiveLayout.addWidget(self.cleanupICacheFilesButton) ## Now parent the FXOption layouts to the options main VBoxLayout self.FXInteractiveMainLayout.addLayout(self.FXInteractiveLayout) ############################### ## BUILD THE FX LIBRARY STUFFS ############################### if context.step['name'] == 'FX' or context.step['name'] == 'Additional FX': self.FXLibGroupBox = QtGui.QGroupBox(self) self.FXLibGroupBox.setTitle('FX Library:') self.FXLibMainLayout = QtGui.QVBoxLayout(self.FXLibGroupBox) ### HORIZONTAL BOX LAYOUT self.fxLibshLayout = QtGui.QGridLayout() j = 0 pos = [ (0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), ] fxNames = [('Boat Splash', fxLib.splashRigger, 'Creates a spherical volumetric emitter that emits sprite as splashes'), ('Splash Tool v1.0', self.openSplashTool,'working'), ('Bubble on selected Mesh(s)', fxLib.bubbleSetup, 'Creates bubble setup on selected mesh'), ('Kill Field', fxLib.nParticle_killField, 'How it works?\n - Creates a uniform field (change-able) volume shapes that kills any particles when in contact.\n - LifespanPP expression line added into runtime after dynamics of nParticleShape.\n - Lifespan mode needs to be changed to lifespanPP in order to work.\n\nUsage\n - Select nParticle(s) and click button.'), ('Wake / Foam Emitter', fluidLib._addWakeEmitter), ('-', fxLib._underConstruction), ('-', fxLib._underConstruction), ('-', fxLib._underConstruction), ('-', fxLib._underConstruction), ('-', fxLib._underConstruction), ] for fxName in fxNames: buttonName = fxName[0] buttonFunc = fxName[1] buttonToolTip = fxName[2] if len(fxName) == 3 else None button = QtGui.QPushButton(buttonName) button.pressed.connect( partial(buttonFunc) ) if buttonToolTip: button.setToolTip(buttonToolTip) self.fxLibshLayout.addWidget(button, pos[j][0], pos[j][1]) j += 1 ### Now parent the FXOption layouts to the options main VBoxLayout self.FXLibMainLayout.addLayout(self.fxLibshLayout) ############################### ## Delete Ocean Setup self.deleteButton = QtGui.QPushButton('Delete Ocean Setup!') self.deleteButton.setFlat(False) self.deleteButton.pressed.connect(partial(fxLib.removeOceanSetup, context.step["name"])) self.deleteButton.setStyleSheet("QPushButton {text-align: center; background: dark red; color: black}") ## Now add to the mainLayout debug(self.app, method = 'Main_UI', message = 'Parenting widgets....', verbose = False) self.mainLayout.addLayout(self.lowhiLayout) self.mainLayout.addWidget(self.animGroupBox) if context.step['name'] == 'FX' or context.step['name'] == 'Additional FX': self.mainLayout.addWidget(self.FXBuildGroupBox) self.mainLayout.addWidget(self.FXViewGroupBox) self.mainLayout.addWidget(self.FXSettingsGroupBox) self.mainLayout.addWidget(self.FXLibGroupBox) self.mainLayout.addWidget(self.FXInteractiveGroupBox) ## Hide the build settings atm because we're not using them self.FXSettingsGroupBox.hide() self.mainLayout.addWidget(self.FXOptionsGroupBox) self.mainLayout.addWidget(self.deleteButton) self.mainLayout.addStretch(1) self.resize(50,120) if context.step['name'] == 'FX' or context.step['name'] == 'Additional FX': self.animGroupBox.hide() self.populatePulldowns() debug(app = self.app, method = 'Main_UI', message= 'self.xRes.value(): %s' % self.xRes.value(), verbose = False) debug(app = self.app, method = 'Main_UI', message= 'self.zRes.value(): %s' % self.zRes.value(), verbose = False) debug(self.app, method = 'Main_UI', message = 'UI Build SUCCESS.', verbose = False) else: QtGui.QMessageBox.information(None, "Aborted...", 'You must have active a current 3D viewport! \nRight click the viewport to build from as we need to use the camera information.') self.parent.close()
def process_result(self, result): """ Process list of tasks retrieved by get_data on the main thread :param result: Dictionary containing the various display & grouping options required to build the file list as well as the list of files organised by task. """ if FileListView.DEBUG_GET_DATA_IN_MAIN_THREAD: # gathering of data was not done in the get_data stage so we # should do it here instead - this method gets called in the # main thread result = self._get_data(result) task_groups = result["task_groups"] task_name_order = result["task_name_order"] task_order = result["task_order"] current_task_name = result["current_task_name"] self._current_filter = result["filter"] self._update_title() if not task_groups: # build a useful error message using the info we have available: msg = "" if not result["can_change_work_area"]: if not result["have_valid_workarea"]: msg = "The current Work Area is not valid!" elif not result["have_valid_configuration"]: msg = ("Shotgun File Manager has not been configured for the environment " "being used by the selected Work Area!") elif not result["can_do_new_file"]: msg = "Couldn't find any files in this Work Area!" else: msg = "Couldn't find any files!\nClick the New file button to start work." else: if not result["have_valid_workarea"]: msg = "The current Work Area is not valid!" elif not result["have_valid_configuration"]: msg = ("Shotgun File Manager has not been configured for the environment " "being used by the selected Work Area!\n" "Please choose a different Work Area to continue.") elif not result["can_do_new_file"]: msg = "Couldn't find any files in this Work Area!\nTry selecting a different Work Area." else: msg = "Couldn't find any files!\nClick the New file button to start work." self.set_message(msg) return for task_name in task_order: name_groups = task_groups[task_name] if (len(task_groups) > 1 or (task_name != current_task_name and task_name != FileListView.NO_TASK_NAME and current_task_name == None)): # add header for task: h = self.add_item(browser_widget.ListHeader) h.set_title("%s" % (task_name)) ordered_names = task_name_order[task_name] for name in ordered_names: details = name_groups[name] files = details["files"] highest_local_file = details.get("highest_local_file") highest_publish_file = details.get("highest_publish_file") thumbnail = details["thumbnail"] # add new item to list: item = self._add_file_item(highest_publish_file, highest_local_file) if not item: continue # set thumbnail if have one: if thumbnail: item.set_thumbnail(thumbnail) # add context menu: item.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) # if it's a publish then add 'View In Shotgun' item: if highest_publish_file: action = QtGui.QAction("View latest Publish in Shotgun", item) # (AD) - the '[()]' syntax in action.triggered[()].connect looks weird right! # 'triggered' is a QtCore.SignalInstance which actually defines multiple # signals: triggered() & triggered(bool). PySide will correctly determine which # one to use but PyQt gets confused and calls the (bool) version instead which # causes problems for us... Luckily, Qt lets us use the argument list () to # index into the SignalInstance object to force the use of the non-bool version - yay! action.triggered[()].connect(lambda f=highest_publish_file: self._on_show_in_shotgun_action_triggered(f)) item.addAction(action) # build context menu for all publish versions: published_versions = [f.version for f in files.values() if f.is_published and isinstance(f.version, int)] if published_versions: published_versions.sort(reverse=True) publishes_action = QtGui.QAction("Open Publish Read-Only", item) publishes_sm = QtGui.QMenu(item) publishes_action.setMenu(publishes_sm) item.addAction(publishes_action) for v in published_versions[:20]: f = files[v] msg = ("v%03d" % f.version) action = QtGui.QAction(msg, publishes_sm) # see above for explanation of [()] syntax in action.triggered[()].connect... action.triggered[()].connect(lambda f=f: self._on_open_publish_action_triggered(f)) publishes_sm.addAction(action) # build context menu for all work files: wf_versions = [f.version for f in files.values() if f.is_local and isinstance(f.version, int)] if wf_versions: wf_versions.sort(reverse=True) wf_action = QtGui.QAction("Open Work File", item) wf_sm = QtGui.QMenu(item) wf_action.setMenu(wf_sm) item.addAction(wf_action) for v in wf_versions[:20]: f = files[v] msg = ("v%03d" % f.version) action = QtGui.QAction(msg, wf_sm) # see above for explanation of [()] syntax in action.triggered[()].connect... action.triggered[()].connect(lambda f=f: self._on_open_workfile_action_triggered(f)) wf_sm.addAction(action)
def __init__(self, parent=None): SystrayWindow.__init__(self, parent) # initialize member variables self.current_project = None self.__activation_hotkey = None self.__pipeline_configuration_separator = None self._settings_manager = settings.UserSettings( sgtk.platform.current_bundle()) # setup the window self.ui = desktop_window.Ui_DesktopWindow() self.ui.setupUi(self) self.project_overlay = overlay_widget.ShotgunOverlayWidget( self.ui.project_commands) self.setup_project_widget = SetupProject(self.ui.project_commands) self.setup_project_widget.setup_finished.connect( self._on_setup_finished) self.update_project_config_widget = UpdateProjectConfig( self.ui.project_commands) self.update_project_config_widget.update_finished.connect( self._on_update_finished) self.setup_new_os_widget = SetupNewOS(self.ui.project_commands) # setup systray behavior self.set_content_layout(self.ui.border_layout) self.set_drag_widgets([self.ui.header, self.ui.footer]) self.systray_state_changed.connect(self.handle_systray_state_changed) QtGui.QApplication.instance().setQuitOnLastWindowClosed(False) # Setup header buttons self.ui.apps_button.setProperty("active", True) self.ui.apps_button.style().unpolish(self.ui.apps_button) self.ui.apps_button.style().polish(self.ui.apps_button) engine = sgtk.platform.current_engine() connection = engine.get_current_user().create_sg_connection() # Setup the console self.__console = Console() self.__console_handler = ConsoleLogHandler(self.__console) engine.add_logging_handler(self.__console_handler) # User menu ########################### user = engine.get_current_login() current_user = connection.find_one("HumanUser", [["id", "is", user["id"]]], ["image", "name"]) self._current_user_id = user["id"] thumbnail_url = current_user.get("image") if thumbnail_url is not None: (_, thumbnail_file) = tempfile.mkstemp(suffix=".jpg") try: shotgun.download_url(connection, thumbnail_url, thumbnail_file) pixmap = QtGui.QPixmap(thumbnail_file) self.ui.user_button.setIcon(QtGui.QIcon(pixmap)) except Exception: # if it fails for any reason, that's alright pass finally: try: os.remove(thumbnail_file) except Exception: pass # populate user menu self.user_menu = QtGui.QMenu(self) name_action = self.user_menu.addAction(current_user["name"]) url_action = self.user_menu.addAction( connection.base_url.split("://")[1]) self.user_menu.addSeparator() self.user_menu.addAction(self.ui.actionPin_to_Menu) self.user_menu.addAction(self.ui.actionKeep_on_Top) self.user_menu.addAction(self.ui.actionShow_Console) self.user_menu.addAction(self.ui.actionRefresh_Projects) about_action = self.user_menu.addAction("About...") self.user_menu.addSeparator() self.user_menu.addAction(self.ui.actionSign_Out) self.user_menu.addAction(self.ui.actionQuit) name_action.triggered.connect(self.open_site_in_browser) url_action.triggered.connect(self.open_site_in_browser) about_action.triggered.connect(self.handle_about) QtGui.QApplication.instance().aboutToQuit.connect( self.handle_quit_action) self.ui.actionPin_to_Menu.triggered.connect(self.toggle_pinned) self.ui.actionKeep_on_Top.triggered.connect(self.toggle_keep_on_top) self.ui.actionShow_Console.triggered.connect( self.__console.show_and_raise) self.ui.actionRefresh_Projects.triggered.connect( self.handle_project_refresh_action) self.ui.actionSign_Out.triggered.connect(self.sign_out) self.ui.actionQuit.triggered.connect(self.handle_quit_action) self.ui.user_button.setMenu(self.user_menu) # Initialize the model to track project commands self._project_command_model = ProjectCommandModel(self) self._project_command_proxy = ProjectCommandProxyModel(self) self._project_command_proxy.setSourceModel(self._project_command_model) self._project_command_proxy.sort(0) self.ui.project_commands.setModel(self._project_command_proxy) # limit how many recent commands are shown self._project_command_proxy.set_recents_limit(6) self._project_command_delegate = ProjectCommandDelegate( self.ui.project_commands) self.ui.project_commands.setItemDelegate( self._project_command_delegate) self.ui.project_commands.expanded_changed.connect( self.handle_project_command_expanded_changed) # fix for floating delegate bug # see discussion at https://stackoverflow.com/questions/15331256 self.ui.project_commands.verticalScrollBar().valueChanged.connect( self.ui.project_commands.updateEditorGeometries) self._project_command_model.command_triggered.connect( engine._handle_button_command_triggered) # load and initialize cached projects self._project_model = SgProjectModel(self, self.ui.projects) self._project_proxy = SgProjectModelProxy(self) # hook up sorting/filtering GUI self._project_proxy.setSourceModel(self._project_model) self._project_proxy.sort(0) self.ui.projects.setModel(self._project_proxy) # tell our project view to use a custom delegate to produce widgets self._project_delegate = \ SgProjectDelegate(self.ui.projects, QtCore.QSize(130, 150)) self.ui.projects.setItemDelegate(self._project_delegate) # handle project selection change self._project_selection_model = self.ui.projects.selectionModel() self._project_selection_model.selectionChanged.connect( self._on_project_selection) # handle project data updated self._project_model.data_refreshed.connect( self._handle_project_data_changed) self.ui.actionProject_Filesystem_Folder.triggered.connect( self.on_project_filesystem_folder_triggered) # setup project search self._search_x_icon = QtGui.QIcon(":/tk-desktop/icon_inbox_clear.png") self._search_magnifier_icon = QtGui.QIcon( ":/tk-desktop/search_transparent.png") self.ui.search_button.clicked.connect(self.search_button_clicked) self.ui.search_text.textChanged.connect(self.search_text_changed) self.search_button_clicked() self.project_carat_up = QtGui.QIcon(":tk-desktop/up_carat.png") self.project_carat_down = QtGui.QIcon(":tk-desktop/down_carat.png") self.down_arrow = QtGui.QIcon(":tk-desktop/down_arrow.png") self.right_arrow = QtGui.QIcon(":tk-desktop/right_arrow.png") self.ui.project_arrow.clicked.connect( self._on_back_to_projects_clicked) self.clear_app_uis() self.ui.shotgun_button.clicked.connect(self.open_site_in_browser) self.ui.shotgun_button.setToolTip("Open Shotgun in browser.\n%s" % connection.base_url) self._project_model.thumbnail_updated.connect( self.handle_project_thumbnail_updated) self._load_settings()
def __init__(self, engine, menu_name): self._engine = engine self._menu_name = menu_name self._handle = QtGui.QMenu(self._menu_name)