Widgets extension
A widget extension is a python file that is meant to visually represent a plugin, allowing the user to interact with the plugin and set the desired options to it before it gets executed. For example the widget can show a combo box where the user can select which camera to export, once selected, this will internally set the camera*selected option in the tool-config.
A widget should always inherit from the BaseWidget which is a mixin of FrameworkWidget and QtWidgets.QWidget.
By default, named <dcc_name>*<description>\_<widget-type>.pyand located in thewidgets folder.
Here is an example of a default widget extension for maya:
# :coding: utf-8
# :copyright: Copyright (c) 2024 ftrack
from Qt import QtWidgets, QtCore
from ftrack_framework_qt.widgets import BaseWidget
from ftrack_qt.utils.decorators import invoke_in_qt_main_thread
class MayaCameraSelectorWidget(BaseWidget):
    '''Main class to represent a scene widget on a publish process.'''
    name = 'maya_camera_selector'
    ui_type = 'qt'
    def __init__(
        self,
        event_manager,
        client_id,
        context_id,
        plugin_config,
        group_config,
        on_set_plugin_option,
        on_run_ui_hook,
        parent=None,
    ):
        self._camera_cb = None
        super(MayaCameraSelectorWidget, self).__init__(
            event_manager,
            client_id,
            context_id,
            plugin_config,
            group_config,
            on_set_plugin_option,
            on_run_ui_hook,
            parent,
        )
    def pre_build_ui(self):
        layout = QtWidgets.QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setAlignment(QtCore.Qt.AlignTop)
        self.setLayout(layout)
        self.setSizePolicy(
            QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed
        )
    def build_ui(self):
        '''build function widgets.'''
        # Create export type combo box
        self._camera_cb = QtWidgets.QComboBox()
        self.layout().addWidget(self._camera_cb)
    def post_build_ui(self):
        '''hook events'''
        self._camera_cb.currentTextChanged.connect(self._on_camera_changed)
    def populate(self):
        '''Fetch info from plugin to populate the widget'''
        self.query_cameras()
    def query_cameras(self):
        '''Query All cameras from scene.'''
        payload = {}
        self.run_ui_hook(payload)
    @invoke_in_qt_main_thread
    def ui_hook_callback(self, ui_hook_result):
        '''Handle the result of the UI hook.'''
        super(MayaCameraSelectorWidget, self).ui_hook_callback(ui_hook_result)
        self._camera_cb.addItems(ui_hook_result)
        default_camera_name = self.plugin_config['options'].get(
            'camera_name', 'persp'
        )
        self._camera_cb.setCurrentText(default_camera_name)
    def _on_camera_changed(self, camera_name):
        '''Updates the camera_name option with the provided *camera_name'''
        if not camera_name:
            return
        self.set_plugin_option('camera_name', camera_name)
If multiple widgets are detected in the extensions_path, having same, the first widget will be the one picked up
based on the order they appear.