diff --git a/avalon/maya/pipeline.py b/avalon/maya/pipeline.py index 74bc11c30..9596fbd1a 100644 --- a/avalon/maya/pipeline.py +++ b/avalon/maya/pipeline.py @@ -137,6 +137,9 @@ def deferred(): enable=False ) + cmds.menuItem("Switch Task", + command=lambda *args: workfiles.show_switch_task(parent=self._parent)) + cmds.setParent("..", menu=True) cmds.menuItem(divider=True) diff --git a/avalon/nuke/pipeline.py b/avalon/nuke/pipeline.py index 18d9b56f8..206959383 100644 --- a/avalon/nuke/pipeline.py +++ b/avalon/nuke/pipeline.py @@ -414,6 +414,9 @@ def _install_menu(): # Create menu menubar = nuke.menu("Nuke") menu = menubar.addMenu(api.Session["AVALON_LABEL"]) + menu.addCommand("Switch Task", + lambda: workfiles.show_switch_task(parent=get_main_window()) + ) _add_contextmanager_menu(menu) diff --git a/avalon/tools/workfiles/__init__.py b/avalon/tools/workfiles/__init__.py index 4f4901158..c18a2398a 100644 --- a/avalon/tools/workfiles/__init__.py +++ b/avalon/tools/workfiles/__init__.py @@ -1,7 +1,9 @@ from .app import ( - show + show, + show_switch_task ) __all__ = [ - "show" + "show", + "show_switch_task" ] diff --git a/avalon/tools/workfiles/app.py b/avalon/tools/workfiles/app.py index 8384deed4..2c8a8ab81 100644 --- a/avalon/tools/workfiles/app.py +++ b/avalon/tools/workfiles/app.py @@ -891,6 +891,127 @@ def _on_task_changed(self): files.refresh() +class SwitchTaskWindow(QtWidgets.QMainWindow): + """Switch Task Window""" + title = "Switch Task" + + def __init__(self, parent=None): + super(SwitchTaskWindow, self).__init__(parent=parent) + self.setWindowTitle(self.title) + self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.WindowCloseButtonHint) + self.setWindowModality(QtCore.Qt.ApplicationModal) + + pages = { + "home": QtWidgets.QWidget() + } + + widgets = { + "pages": QtWidgets.QStackedWidget(), + "body": QtWidgets.QWidget(), + "assets": AssetWidget(), + "tasks": TasksWidget(), + "switch": QtWidgets.QPushButton("Switch") + } + + self.setCentralWidget(widgets["pages"]) + widgets["pages"].addWidget(pages["home"]) + + # Build home + layout = QtWidgets.QVBoxLayout(pages["home"]) + layout.addWidget(widgets["body"]) + + # Build home - body + layout = QtWidgets.QVBoxLayout(widgets["body"]) + split = QtWidgets.QSplitter() + split.addWidget(widgets["assets"]) + split.addWidget(widgets["tasks"]) + split.setStretchFactor(0, 1) + split.setStretchFactor(1, 1) + layout.addWidget(split) + layout.addWidget(widgets["switch"]) + + # Add top margin for tasks to align it visually with files as + # the files widget has a filter field which tasks does not. + widgets["tasks"].setContentsMargins(0, 32, 0, 0) + + # Connect signals + widgets["assets"].current_changed.connect(self.on_asset_changed) + widgets["tasks"].task_changed.connect(self.on_task_changed) + widgets["switch"].clicked.connect(self.on_switch) + + self.widgets = widgets + self.refresh() + + self.resize(600, 600) + + def on_task_changed(self): + tools_lib.schedule(self._on_task_changed, 100, channel="mongo") + + def on_asset_changed(self): + tools_lib.schedule(self._on_asset_changed, 50, channel="mongo") + + def on_switch(self): + asset = self.widgets["assets"].get_active_asset_document() + task = self.widgets["tasks"].get_current_task() + """Enter the asset and task session currently selected""" + + session = api.Session.copy() + changes = pipeline.compute_session_changes(session, + asset=asset, + task=task) + if not changes: + # Return early if we're already in the right Session context + # to avoid any unwanted Task Changed callbacks to be triggered. + self.close() + return + + api.update_current_task(asset=asset, task=task) + self.close() + + def set_context(self, context): + + if "asset" in context: + asset = context["asset"] + asset_document = io.find_one({ + "name": asset, + "type": "asset" + }) + + # Select the asset + self.widgets["assets"].select_assets([asset], expand=True) + + # Force a refresh on Tasks? + self.widgets["tasks"].set_asset(asset_document) + + if "task" in context: + self.widgets["tasks"].select_task(context["task"]) + + def refresh(self): + + # Refresh asset widget + self.widgets["assets"].refresh() + + self.on_task_changed() + + def _on_asset_changed(self): + asset = self.widgets["assets"].get_active_asset_document() + + if not asset: + # Force disable the other widgets if no + # active selection + self.widgets["tasks"].setEnabled(False) + else: + self.widgets["tasks"].setEnabled(True) + + self.widgets["tasks"].set_asset(asset) + + def _on_task_changed(self): + asset = self.widgets["assets"].get_active_asset_document() + task = self.widgets["tasks"].get_current_task() + self.widgets["tasks"].setEnabled(bool(asset)) + self.widgets["switch"].setEnabled(all([bool(task), bool(asset)])) + + def show(root=None, debug=False, parent=None, use_context=True): """Show Work Files GUI""" # todo: remove `root` argument to show() @@ -942,3 +1063,35 @@ def show(root=None, debug=False, parent=None, use_context=True): # Pull window to the front. module.window.raise_() module.window.activateWindow() + + +def show_switch_task(parent=None, use_context=True): + """Show Switch Task GUI""" + + if module.window: + module.window.close() + del(module.window) + + host = api.registered_host() + if host is None: + raise RuntimeError("No registered host.") + + with tools_lib.application(): + + window = SwitchTaskWindow(parent=parent) + window.refresh() + + if use_context: + context = {"asset": api.Session["AVALON_ASSET"], + "silo": api.Session["AVALON_SILO"], + "task": api.Session["AVALON_TASK"]} + window.set_context(context) + + window.show() + window.setStyleSheet(style.load_stylesheet()) + + module.window = window + + # Pull window to the front. + module.window.raise_() + module.window.activateWindow()