python.tk_houdini.ui_generation

Module Contents

Classes

AppCommand

Wraps around a single command that you get from engine.commands

AppCommandsMenu

Base class for interface elements that trigger command actions.

AppCommandsPanelHandler

Creates panels and installs them into the session.

AppCommandsShelf

Base class for interface elements that trigger command actions.

AppCommandsUI

Base class for interface elements that trigger command actions.

Functions

_format_xml(xml)

Do any required formatting. Typically before writing to disk.

_jump_to_fs(engine)

Jump from context to Fs

_jump_to_sg(engine)

Jump from context to Sg

_on_file_change_timeout()

Checks to see if the current file has changed. If it has, try to set the

_write_xml(xml, xml_path)

Write the full element tree to the supplied xml file.

ensure_file_change_timer_running()

Ensures a timer is running to periodically check for current file change.

get_registered_commands(engine)

Returns a list of AppCommands for the engine’s registered commands.

get_registered_panels(engine)

Returns a list of AppCommands for the engine’s registered panels.

get_wrapped_panel_widget(engine, widget_class, bundle, title)

Returns a wrapped widget for use in a houdini python panel.

_g_dynamic_menu_names = Multiline-String[source]
Show Value
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
engine = None
menu_items = []
try:
    import tank.platform.engine
    engine = tank.platform.engine.current_engine()
    if engine:
        # the commands to display in this menu
        cmds = engine._menu.%s()
        # build the list that houdini expects
        for cmd in cmds:
            menu_items.extend([cmd.get_id(), cmd.name])
    else:
        menu_items.extend(["tk.houdini.menu.no.shotgun", "Toolkit is disabled - Click for details"])
except Exception as e:
    import traceback
    error = traceback.format_exc()
    if engine:
        # store the exception on the menu object for display in the callback
        engine._menu._menu_error = Exception(str(e) + ". " + error)
    # just give houdini a special error item for the menu
    menu_items.extend(
        ["tk.houdini.menu.error", "Menu Error. Click for Details..."])
else:
    if engine:
        engine._menu._menu_error = None
finally:
    return menu_items
_g_dynamic_menu_script = Multiline-String[source]
Show Value
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import hou
engine = None
try:
    import tank.platform.engine
    # get the selected menu id
    command_id = kwargs["selectedtoken"]
    engine = tank.platform.engine.current_engine()
    # special id if there is no shotgun context/engine
    if command_id == "tk.houdini.menu.no.shotgun":
        msg = (
            "It appears as though you are not currently working in a Shotgun "
            "context. There is no Shotgun for Houdini Engine running so no "
            "menu or shelf items are available. In order to restart the Shotgun "
            "integration, please close and reopen Houdini or choose a file "
            "from your Shotgun project in the 'Recent Files' menu. If you "
            "believe this to be an error, please contact your support team."
        )
        hou.ui.displayMessage(msg, severity=hou.severityType.Warning)
    # special id if errors occurred and they clicked for more info
    if command_id == "tk.houdini.menu.error":
        # try to locate the exception on the menu object and raise it
        if engine._menu._menu_error:
            raise engine._menu._menu_error
        # no stored exception, tell the user to look in the shell
        else:
            raise Exception("The error message should show up in your shell.")
    # the special context item. launch the context in browser
    if command_id == engine._menu._context_menu_item_id:
        from tank.platform.qt import QtCore, QtGui
        url = engine.context.shotgun_url
        QtGui.QDesktopServices.openUrl(QtCore.QUrl(url))
    # should be a registered command. launch it
    else:
        engine.launch_command(command_id)
except Exception as e:
    # handle any exceptions raised during menu building
    msg = "An error occurred building the Shotgun menu...\n\n%s" % (e,)
    if engine:
        hou.ui.displayMessage(msg, severity=hou.severityType.Error)
    else:
        print(msg)
_g_launch_script = Multiline-String[source]
Show Value
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import hou
import tank.platform.engine

engine = tank.platform.engine.current_engine()
if engine is None or not hasattr(engine, 'launch_command'):
    msg = "Shotgun: Houdini engine is not loaded."
    if hou.isUIAvailable():
        hou.ui.displayMessage(msg)
    else:
        print(msg)
else:
    engine.launch_command('%s')
_g_panel_script = Multiline-String[source]
Show Value
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
from sgtk.platform.qt import QtCore, QtGui

class NoPanelWidget(QtGui.QWidget):

    def __init__(self, msg, error=None):

        super(NoPanelWidget, self).__init__()

        sg_icon_path = '%s'
        sg_icon = QtGui.QLabel()

        try:
            sg_pixmap = QtGui.QPixmap(sg_icon_path).scaledToWidth(64, QtCore.Qt.SmoothTransformation)
            sg_icon.setPixmap(sg_pixmap)
        except:
            pass

        msg_lbl = QtGui.QLabel(msg)
        msg_lbl.setWordWrap(True)

        if error:
            error_txt = QtGui.QTextEdit(error)
            error_txt.setReadOnly(True)

        h_layout = QtGui.QHBoxLayout()
        h_layout.setSpacing(5)
        h_layout.addWidget(sg_icon)
        h_layout.addWidget(msg_lbl)
        h_layout.setStretchFactor(msg_lbl, 10)

        v_layout = QtGui.QVBoxLayout(self)
        v_layout.setContentsMargins(10, 10, 10, 10)
        v_layout.setSpacing(15)
        v_layout.addStretch()
        v_layout.addLayout(h_layout)
        if error:
            v_layout.addWidget(error_txt)
        v_layout.addStretch()

def createInterface():

    try:
        import tank.platform.engine
    except ImportError:
        return NoPanelWidget(
            "It looks like you're running Houdini outside of a Shotgun "
            "context. Next time you launch Houdini from within a Shotgun "
            "context, you will see the '%s' panel here."
        )

    try:
        engine = tank.platform.engine.current_engine()
        panel_info = engine.get_panel_info('%s')
        panel_widget = engine.get_wrapped_panel_widget(
            engine,
            panel_info['widget_class'],
            panel_info['bundle'],
            panel_info['title'],
        )
        panel_widget.apply_stylesheet()
    except Exception:
        import traceback
        return NoPanelWidget(
            "There was a problem loading this panel! The error message "
            "is provided below.",
            error=traceback.format_exc()
        )

    pane_tab = kwargs["paneTab"]

    # it appears that sometimes the pane_tab available here is not the one
    # we're interested in. sometimes it is not set and sometimes it is a
    # different tab all together. so just check to make sure it is set and
    # make sure it has the 'setLabel' method available. that at least implies
    # that it is a python panel
    if pane_tab and hasattr(pane_tab, 'setLabel'):
        title = panel_info.get('title')
        if title:
            pane_tab.setLabel(title)

            # We're caching here based on title, because it's the
            # bit of information we have that's reliably available
            # from all of the various methods of showing this
            # pane tab. We cache the pane tab's name so that if a
            # second invokation of showing this particular panel is
            # triggered, we just show that panel rather than opening
            # a second instance.
            engine._pane_cache[title] = pane_tab.name()

    return panel_widget
g_current_file[source]
g_file_change_timer[source]
g_menu_item_script[source]
class AppCommand(name, command_dict)[source]

Bases: object

Wraps around a single command that you get from engine.commands

get_app_instance_name(self)[source]
get_app_name(self)[source]
get_description(self)[source]
get_documentation_url_str(self)[source]
get_icon(self)[source]
get_id(self)[source]
get_type(self)[source]
class AppCommandsMenu(engine, commands)[source]

Bases: python.tk_houdini.ui_generation.AppCommandsUI

Base class for interface elements that trigger command actions.

_build_shotgun_menu_item(self)[source]

Constructs a top-level “Shotgun” menu.

Same logic for both the static and dynamic menu.

Returns

tuple containing the root element and the shotgun menu item

_create_dynamic_menu(self, xml_path)[source]

Construct the dynamic Shotgun menu for toolkit in Houdini 15+.

Parameters

xml_path – The path to the xml file to store the menu definitions

_create_static_menu(self, xml_path)[source]

Construct the static Shotgun menu for older versions of Houdini.

Parameters

xml_path – The path to the xml file to store the menu definitions

_get_commands_by_app(self)[source]

This method returns a flattened list of registered app commands.

This is called directly as a part of the dynamic menu generation code as houdini builds submenus when the user clicks on the top-level Shotgun menu. This should execute quickly.

_get_context_commands(self)[source]

This method returns a modified list of context commands.

This is called directly as a part of the dynamic menu generation code as houdini builds submenus when the user clicks on the top-level Shotgun menu. This should execute quickly.

_itemNode(self, parent, label, id)[source]

Constructs a static menu item for the supplied parent.

Adds the script path and args which houdini uses as the callback.

_menuNode(self, parent, label, id)[source]

Constructs a submenu for the supplied parent.

create_menu(self, xml_path)[source]

Create the Shotgun Menu

class AppCommandsPanelHandler(engine, commands, panel_commands)[source]

Bases: python.tk_houdini.ui_generation.AppCommandsUI

Creates panels and installs them into the session.

create_panels(self, panels_file)[source]

Create the registered panels.

class AppCommandsShelf(engine, commands=None, name='Shotgun', label='Shotgun')[source]

Bases: python.tk_houdini.ui_generation.AppCommandsUI

Base class for interface elements that trigger command actions.

create_shelf(self, shelf_file)[source]

Creates a Shotgun shelf with a tool button for each command.

shelf_file:

The xml file where the shelf definition will be written

create_tool(self, shelf_file, cmd)[source]

Create a new shelf tool.

cmd:

The AppCommand to create a shelf tool for.

shelf_file:

The shelf file to write the tool definition to.

destroy_shelf(self)[source]

Destroy the shelf and all of its tools.

destroy_tools(self)[source]

Destroy the tools on the shelf, leaving a blank shelf.

class AppCommandsUI(engine, commands)[source]

Bases: object

Base class for interface elements that trigger command actions.

_get_context_name(self)[source]

Returns a display name for the current context

_group_commands(self)[source]

This method provides a consistent method for organizing commands.

Used by the menu and shelf classes to collect the registered commands into groups. The method returns a tuple with the first item being a list of context-specific commands, the second item is a dictionary of commands organized by the app name, and the third item is a list of favourite commands as defined in the settings.

_format_xml(xml)[source]

Do any required formatting. Typically before writing to disk.

_jump_to_fs(engine)[source]

Jump from context to Fs

_jump_to_sg(engine)[source]

Jump from context to Sg

_on_file_change_timeout()[source]

Checks to see if the current file has changed. If it has, try to set the new context for the file.

_write_xml(xml, xml_path)[source]

Write the full element tree to the supplied xml file.

Parameters
  • xml (string) – The xml to write to disk

  • xml_path (string) – The path to write the xml.

Also ensures the directory exists before writing the file.

ensure_file_change_timer_running()[source]

Ensures a timer is running to periodically check for current file change.

get_registered_commands(engine)[source]

Returns a list of AppCommands for the engine’s registered commands.

Parameters

engine – The engine to return registered commands for

NOTE: This method currently returns additional panel commands that are not registered, but always present in the shotgun menu and shelves. Those commands are:

“Jump to Shotgun” “Jump to File System”

get_registered_panels(engine)[source]

Returns a list of AppCommands for the engine’s registered panels.

Parameters

engine – The engine to return registered panel commands for

get_wrapped_panel_widget(engine, widget_class, bundle, title)[source]

Returns a wrapped widget for use in a houdini python panel.

Parameters
  • engine – The engine instance.

  • widget_class – The widget class to wrap.

  • bundle – The bundle associated with the panel being wrapped.

  • title – The title to display for this panel.

Here we subclass the panel widget in order to hijack the first paint event. There, we force clear the parent’s stylesheet and reset the widget with the bundled stylesheet if there is one. This prevents houdini’s parenting from cramping the panel’s style. We also filter for change events to detect when something else attempts to change the style so we can force it back to the bundled style. The first paint event isn’t sufficient for panels saved in desktops, but detecting style change seems to do the trick.