Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 18 additions & 19 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
# By accessing, using, copying or modifying this work you indicate your
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Shotgun Software Inc.
import os
import sgtk
from tank.util import sgre as re

logger = sgtk.platform.get_logger(__name__)

Expand Down Expand Up @@ -40,29 +38,17 @@ def init_app(self):
# make the base plugins available via the app
self._base_hooks = tk_multi_publish2.base_hooks

display_name = self.get_setting("display_name")
# "Publish Render" ---> publish_render
command_name = display_name.lower()
# replace all non alphanumeric characters by '_'
command_name = re.sub(r"[^0-9a-zA-Z]+", "_", command_name)

self.modal = self.get_setting("modal")

pre_publish_hook_path = self.get_setting(self.CONFIG_PRE_PUBLISH_HOOK_PATH)
self.pre_publish_hook = self.create_hook_instance(pre_publish_hook_path)

# register command
cb = lambda: tk_multi_publish2.show_dialog(self)
menu_caption = "%s..." % display_name
menu_options = {
"short_name": command_name,
"description": "Publishing of data to Flow Production Tracking",
# dark themed icon for engines that recognize this format
"icons": {
"dark": {"png": os.path.join(self.disk_location, "icon_256_dark.png")}
},
}
self.engine.register_command(menu_caption, cb, menu_options)
self.engine.register_command(
self.display_hook.menu_name,
lambda: tk_multi_publish2.show_dialog(self),
properties=self.display_hook.menu_properties,
)

@property
def base_hooks(self):
Expand All @@ -83,6 +69,19 @@ def base_hooks(self):
"""
return self._base_hooks

@property
def display_hook(self) -> sgtk.Hook:
"""Exposes the extensible ``:display:hook`` instance from app settings.

Used to fetch information related to the display and UI of the app.
"""
self._display_hook = getattr(
self,
"_display_hook",
self.create_hook_instance(self.get_setting("display")["hook"]),
)
return self._display_hook

@property
def util(self):
"""
Expand Down
158 changes: 158 additions & 0 deletions docs/hooks.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
Hooks
=====

Apart from the core collector and publish plugin hooks and settings, many other
parts of the publishing process and GUI can be customized by defining and extending
various hook configurations. The specifications are defined in the ``info.yml``
file at the root of the code repository.


Publishing
----------

.. code-block:: yaml
:caption: info.yml

post_phase:
type: hook
description:
"A hook that defines logic to be executed after each phase of publish
execution including validation, publish, and finalization. This allows
for very specific curation and customization of the publish tree
during a publish session. Serializing the publish tree to disk after
validation, for example is possible via this hook."
default_value: "{self}/post_phase.py"

pre_publish:
type: hook
description:
"This hook defines logic to be executed before showing the publish
dialog. There may be conditions that need to be checked before allowing
the user to proceed to publishing."
default_value: "{self}/pre_publish.py"

path_info:
type: hook
description:
"This hook contains methods that are used during publishing to infer
information from file paths. This includes version and frame number
identification, publish display name, image sequence paths, etc."
default_value: "{self}/path_info.py"

thumbnail_generator:
type: hook
description:
"This hook contains methods that are used during publishing to auto
generate a thumbnail from the file being published."
default_value: "{self}/thumbnail_generator.py"

GUI
---

For basic GUI customizations, these configurations can be used/modified:

.. code-block:: yaml
:caption: info.yml

display_name:
type: str
default_value: Publish
description: Specify the name that should be used in menus and the main
publish dialog

display_action_name:
type: str
default_value: Publish
description: "Shorter version of display_name setting, used as button name."


Display Hook and Settings
^^^^^^^^^^^^^^^^^^^^^^^^^

.. versionadded:: v2.x.x
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left this as v2.x.x as I'm not sure how the merge and release process goes from Autodesk's side, but this should be changed prior to release


When more advanced GUI customizations are needed, the ``display`` configuration
can be used to extend and customize the display hook and any settings to feed into
it.

.. code-block:: yaml
:caption: info.yml

display:
type: dict
description: Hook and settings that implements the values of various GUI
elements of the publish dialog such as window title, menu name
that launches the dialog, button label, etc.
items:
hook: {type: hook}
settings: {type: dict, allows_empty: True}
default_value:
hook: "{self}/display_hook.py"
settings: {}

By default, it uses the values from ``display_name`` and ``display_action_name``
configurations across various menu text, window title, button label, etc.

These can all be overridden as much as needed. The ``display:settings`` values
are free for developers to define and use as they see fit for their custom
``display:hook`` implementations.

Here is an exaggerated simple example where each part are defined via custom
``display:settings``, except ``menu_properties()`` which remains inherited from the
default ``{self}/display_hook.py``.

.. code-block:: yaml
:caption: Example tk-config-default2/env/includes/settings/tk-multi-publish2.yml
:emphasize-lines: 11-19

settings.tk-multi-publish2.standalone:
collector: "{self}/collector.py"
publish_plugins:
- name: Publish to Flow Production Tracking
hook: "{self}/publish_file.py"
settings: {}
- name: Upload for review
hook: "{self}/upload_version.py"
settings: {}
help_url: *help_url
display:
hook:
"{self}/display_hook.py\
:{config}/hooks/tk-multi-publish2/display_hook.py"
settings:
action_name: Verb
button_name: Click Me
window_title: I'm Here
menu_name: Publish Stuff
location: "@apps.tk-multi-publish2.location"

.. code-block:: python
:caption: Example tk-config-default2/hooks/tk-multi-publish2/display_hook.py

import sgtk

HookBaseClass = sgtk.get_hook_baseclass()


class SettingsBasedDisplayHook(HookBaseClass):
"""Hook that defines how the action to show the publish dialog is displayed."""

@property
def action_name(self) -> str:
"""Text (verb) used when referring to the _Publish_ action in the GUI."""
return self.settings["action_name"]

@property
def button_name(self) -> str:
"""Label text used for the _Publish_ button."""
return self.settings["button_name"]

@property
def window_title(self) -> str:
"""Window title used for `.Engine.show_modal`/`.Engine.show_dialog`."""
return self.settings["window_title"]

@property
def menu_name(self) -> str:
"""Command name used when registering the show dialog command to menus."""
return self.settings["menu_name"]
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,4 @@ for publish workflow building and customization.
logging
utility
application
hooks
76 changes: 76 additions & 0 deletions hooks/display_hook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright (c) 2026 Autodesk.
#
# CONFIDENTIAL AND PROPRIETARY
#
# This work is provided "AS IS" and subject to the ShotGrid Pipeline Toolkit
# Source Code License included in this distribution package. See LICENSE.
# By accessing, using, copying or modifying this work you indicate your
# agreement to the ShotGrid Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Autodesk.
"""Hook that defines how the command/action to show the publish dialog is displayed.

The output of methods in this hook are used as follows when calling
`.sgtk.platform.Application.register_command`::

app.register_command(
app.execute_hook_method("display_hook", "menu_name"),
...,
properties=app.execute_hook_method("display_hook", "menu_properties"),
)
"""

import os
import re
from typing import Any

import sgtk

HookBaseClass = sgtk.get_hook_baseclass()


class DisplayHook(HookBaseClass):
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this default implementation be moved into base_hooks?

"""Hook that defines how the action to show the publish dialog is displayed."""

@property
def settings(self) -> dict[str, Any]:
"""Return the settings that are available for this hook."""
return self.parent.get_setting("display").get("settings") or {}

@property
def action_name(self) -> str:
"""Text (verb) used when referring to the _Publish_ action in the GUI."""
return self.parent.get_setting("display_action_name")

@property
def button_name(self) -> str:
"""Label text used for the _Publish_ button."""
return self.action_name

@property
def window_title(self) -> str:
"""Window title used for `.Engine.show_modal`/`.Engine.show_dialog`."""
return self.parent.get_setting("display_name")

@property
def menu_name(self) -> str:
"""Command name used when registering the show dialog command to menus."""
return f"{self.parent.get_setting('display_name')}..."

@property
def menu_properties(self) -> dict[str, Any]:
"""Properties used when registering the show dialog command.

See expected property details at `.sgtk.platform.Application.register_command`.
"""
display_name = self.parent.get_setting("display_name")
command_name = re.sub(r"[^0-9a-zA-Z]+", "_", display_name.lower())

return {
"short_name": command_name,
"description": "Publishing of data to Flow Production Tracking",
"icons": {
"dark": {
"png": os.path.join(self.parent.disk_location, "icon_256_dark.png")
}
},
}
12 changes: 12 additions & 0 deletions info.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ configuration:
description: Specify the name that should be used in menus and the main
publish dialog

display:
type: dict
description: Hook and settings that implements the values of various GUI
elements of the publish dialog such as window title, menu name
that launches the dialog, button label, etc.
items:
hook: {type: hook}
settings: {type: dict, allows_empty: True}
default_value:
hook: "{self}/display_hook.py"
settings: {}

display_action_name:
type: str
default_value: Publish
Expand Down
2 changes: 1 addition & 1 deletion python/tk_multi_publish2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def show_dialog(app):
# defer imports so that the app works gracefully in batch modes
from .dialog import AppDialog

display_name = sgtk.platform.current_bundle().get_setting("display_name")
display_name = sgtk.platform.current_bundle().display_hook.window_title

if app.pre_publish_hook.validate():
# start ui
Expand Down
4 changes: 2 additions & 2 deletions python/tk_multi_publish2/dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,8 @@ def __init__(self, parent=None):
self._summary_thumbnail = None

# set publish button text
self._display_action_name = self._bundle.get_setting("display_action_name")
self.ui.publish.setText(self._display_action_name)
self._display_action_name = self._bundle.display_hook.action_name
self.ui.publish.setText(self._bundle.display_hook.button_name)

# Special UI tweaks based on the 'manual_load_enabled' property
#
Expand Down
Loading