def __init__(self, parent=None, *args, **kwargs):
        super(CreateControllerLayout, self).__init__(*args, **kwargs)
        self.setupUi(self)

        # Create Button Groups (because we get compile errors if
        # trying to create these in the .ui file).
        self.node_type_btnGrp = QtWidgets.QButtonGroup()
        self.node_type_btnGrp.addButton(self.group_rdo_btn)
        self.node_type_btnGrp.addButton(self.locator_rdo_btn)

        self.bake_mode_btnGrp = QtWidgets.QButtonGroup()
        self.bake_mode_btnGrp.addButton(self.full_bake_rdo_btn)
        self.bake_mode_btnGrp.addButton(self.smart_bake_rdo_btn)
        self.bake_mode_btnGrp.addButton(self.current_frame_rdo_btn)

        self.space_btnGrp = QtWidgets.QButtonGroup()
        self.space_btnGrp.addButton(self.world_space_rdo_btn)
        self.space_btnGrp.addButton(self.object_space_rdo_btn)
        self.space_btnGrp.addButton(self.screen_space_rdo_btn)

        # Create Connections
        self.main_object_btn.clicked.connect(self.get_main_object)
        self.pivot_object_btn.clicked.connect(self.get_pivot_object)
        self.smart_bake_rdo_btn.clicked.connect(
            self.smart_bake_radio_button_clicked)
        self.full_bake_rdo_btn.clicked.connect(
            self.fullbake_space_radio_button_clicked)
        self.current_frame_rdo_btn.clicked.connect(
            self.fullbake_space_radio_button_clicked)

        self.reset_options()
Ejemplo n.º 2
0
def create_help_menu_items(menu, tool_help_func=None):
    label = 'Tool Help...'
    if callable(tool_help_func) is False:
        label = 'Help...'
        tool_help_func = _launch_default_help_page
    tooltip = 'Show help for this tool.'
    action = QtWidgets.QAction(label, menu)
    action.setStatusTip(tooltip)
    action.triggered.connect(tool_help_func)
    menu.addAction(action)

    label = 'System Information...'
    tooltip = 'Display detailed information about software and hardware.'
    action = QtWidgets.QAction(label, menu)
    action.setStatusTip(tooltip)
    action.triggered.connect(_launch_sysinfo_window)
    menu.addAction(action)

    label = 'About mmSolver...'
    tooltip = 'About the Maya MatchMove Solver project.'
    action = QtWidgets.QAction(label, menu)
    action.setStatusTip(tooltip)
    action.triggered.connect(_launch_about_window)
    menu.addAction(action)
    return
Ejemplo n.º 3
0
    def add_menus(self, menubar):
        edit_menu = QtWidgets.QMenu('Edit', menubar)
        commonmenus.create_edit_menu_items(
            edit_menu, reset_settings_func=self.reset_options)
        menubar.addMenu(edit_menu)

        help_menu = QtWidgets.QMenu('Help', menubar)
        commonmenus.create_help_menu_items(help_menu,
                                           tool_help_func=_open_help)
        menubar.addMenu(help_menu)
    def createTreeView(self):
        """
        Set up the tree view.
        """
        self.treeView = attr_treeview.AttributeTreeView()
        self.ui.treeViewLayout.addWidget(self.treeView)

        root = attr_nodes.PlugNode('root')
        self.model = attr_nodes.AttrModel(root, font=self.font)
        self.filterModel = QtCore.QSortFilterProxyModel()
        self.filterModel.setSourceModel(self.model)
        self.filterModel.setDynamicSortFilter(False)
        self.header = QtWidgets.QHeaderView(QtCore.Qt.Horizontal,
                                            parent=self.treeView)
        Qt.QtCompat.QHeaderView.setSectionResizeMode(
            self.header, QtWidgets.QHeaderView.ResizeToContents)
        self.treeView.setHeader(self.header)

        self.treeView.setModel(self.filterModel)
        self.treeView.setSortingEnabled(True)
        self.treeView.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.treeView.setSelectionMode(
            QtWidgets.QAbstractItemView.MultiSelection)
        self.selModel = self.treeView.selectionModel()
        self.selModel.selectionChanged.connect(self.selectionChanged)

        # Always hide the UUID Column - it's used for selection of
        # ModelIndexes with Maya node UUIDs only.
        hidden = True
        column = self.model.getColumnIndexFromColumnName(
            const.ATTR_COLUMN_NAME_UUID)
        self.treeView.setColumnHidden(column, hidden)
        return
Ejemplo n.º 5
0
 def check_name_exists(self, rigName, name, rigsList):
     valid_name_list = False
     same_name_used = False
     sel = cmds.ls(transforms=True, os=True) or []
     if len(sel) == 0:
         LOG.warn('Atleast one Transform node type object must be selected.')
         return valid_name_list, same_name_used
     if len(name) == 0:
         LOG.warn('Please type name first.')
         return valid_name_list, same_name_used
     names = name.split(',')
     if len(names) != len(sel):
         LOG.warn('Selection and name count not matching.')
         return valid_name_list, same_name_used
     valid_name_list = True
     for name_item in names:
         # Check if name already exists
         iterator = QtWidgets.QTreeWidgetItemIterator(rigsList)
         while iterator.value():
             item = iterator.value()
             item_name = item.text(0)
             item_name = item_name.replace(rigName, '')
             if item_name == name_item:
                 same_name_used = True
             iterator += 1
     if same_name_used is True:
         LOG.warn('Same name exists already please type different name.')
     return valid_name_list, same_name_used
Ejemplo n.º 6
0
 def createEditor(self, parent, option, index):
     if not index.isValid():
         LOG.warning('Invalid index: %r', index)
         return
     data = index.data(QtCore.Qt.EditRole)
     values = self.getValueList()
     model = QtCore.QStringListModel(values)
     widget = QtWidgets.QComboBox(parent)
     widget.setModel(model)
     return widget
Ejemplo n.º 7
0
def create_edit_menu_items(menu, reset_settings_func=None):
    with_reset_settings = callable(reset_settings_func) is True

    label = 'Reset Settings'
    tooltip = "Reset the current tools's Settings."
    action = QtWidgets.QAction(label, menu)
    action.setStatusTip(tooltip)
    action.setEnabled(with_reset_settings)
    if with_reset_settings is True:
        action.triggered.connect(reset_settings_func)
    menu.addAction(action)
    return
    def contextMenuEvent(self, event):
        LOG.debug('Object TreeView Context Menu Event: %r', event)
        menu = QtWidgets.QMenu(self)

        label = 'Select Marker / Bundle'
        swap_sel_act = QtWidgets.QAction(label, self)
        swap_sel_act.triggered.connect(self.selection_swap)

        label = 'Select Marker + Bundle'
        both_sel_act = QtWidgets.QAction(label, self)
        both_sel_act.triggered.connect(self.selection_both_markers_bundles)

        label = 'Marker Bundle Rename...'
        rename_act = QtWidgets.QAction(label, self)
        rename_act.triggered.connect(self.rename_marker_bundles)

        menu.addAction(swap_sel_act)
        menu.addAction(both_sel_act)
        menu.addSeparator()
        menu.addAction(rename_act)
        menu.exec_(event.globalPos())
        return
Ejemplo n.º 9
0
    def createToolButtons(self):
        """
        Create the 'toggle' buttons for the Object browser.
        """
        self.toggleCamera_toolButton = QtWidgets.QToolButton(self)
        self.toggleCamera_toolButton.setText('CAM')
        self.toggleCamera_toolButton.setCheckable(True)
        self.ui.toggleButtons_layout.addWidget(self.toggleCamera_toolButton)

        self.toggleMarker_toolButton = QtWidgets.QToolButton(self)
        self.toggleMarker_toolButton.setText('MKR')
        self.toggleMarker_toolButton.setCheckable(True)
        self.ui.toggleButtons_layout.addWidget(self.toggleMarker_toolButton)

        self.toggleBundle_toolButton = QtWidgets.QToolButton(self)
        self.toggleBundle_toolButton.setText('BND')
        self.toggleBundle_toolButton.setCheckable(True)
        self.ui.toggleButtons_layout.addWidget(self.toggleBundle_toolButton)

        self.toggleCamera_toolButton.clicked.connect(self.toggleCameraClicked)
        self.toggleMarker_toolButton.clicked.connect(self.toggleMarkerClicked)
        self.toggleBundle_toolButton.clicked.connect(self.toggleBundleClicked)
        return
    def createToolButtons(self):
        """
        Create the 'toggle' buttons for the Attribute browser.
        """
        self.toggleAnimated_toolButton = QtWidgets.QToolButton(self)
        self.toggleAnimated_toolButton.setText('ANM')
        self.toggleAnimated_toolButton.setCheckable(True)
        self.ui.toggleButtons_layout.addWidget(self.toggleAnimated_toolButton)

        self.toggleStatic_toolButton = QtWidgets.QToolButton(self)
        self.toggleStatic_toolButton.setText('STC')
        self.toggleStatic_toolButton.setCheckable(True)
        self.ui.toggleButtons_layout.addWidget(self.toggleStatic_toolButton)

        self.toggleLocked_toolButton = QtWidgets.QToolButton(self)
        self.toggleLocked_toolButton.setText('LCK')
        self.toggleLocked_toolButton.setCheckable(True)
        self.ui.toggleButtons_layout.addWidget(self.toggleLocked_toolButton)

        self.toggleAnimated_toolButton.clicked.connect(
            self.toggleAnimatedClicked)
        self.toggleStatic_toolButton.clicked.connect(self.toggleStaticClicked)
        self.toggleLocked_toolButton.clicked.connect(self.toggleLockedClicked)
        return
Ejemplo n.º 11
0
    def __init__(self, parent=None, *args, **kwargs):
        super(CameraBodyTrackScaleRigBakeLayout,
              self).__init__(*args, **kwargs)
        self.setupUi(self)

        # Create Button Groups (because we get compile errors if
        # trying to create these in the .ui file).
        self.scale_rig_type_btnGrp = QtWidgets.QButtonGroup()
        self.scale_rig_type_btnGrp.addButton(self.cameraTrackScaleRadioButton)
        self.scale_rig_type_btnGrp.addButton(self.bodyTrackScaleRadioButton)

        # Create connections
        self.sceneGetButton.clicked.connect(self.scene_get_button_clicked)
        self.rigsGetButton.clicked.connect(self.controls_get_button_clicked)
        self.cameraTrackScaleRadioButton.toggled.connect(
            self.scale_rig_options_changed)
        self.bodyTrackScaleRadioButton.toggled.connect(
            self.scale_rig_options_changed)

        self.populate_ui()
Ejemplo n.º 12
0
def getParent():
    """
    Get the parent Qt QApplication object.

    Only supports hosts 'standalone' and 'maya'.

    :return: Qt object for the top level parent object.
    """
    host = getHostApplication()

    # try running outside of maya
    app = None
    parent = None
    if host == 'standalone':
        app = QtWidgets.QApplication(sys.argv)
        parent = None
    elif host == 'maya':
        parent = getMayaMainWindow()
    else:
        msg = 'Host application is not valid: host=%r'
        raise ValueError(msg % host)
    return app, parent
Ejemplo n.º 13
0
    def __init__(self, parent=None, *args, **kwargs):
        super(ScreenSpaceRigBakeLayout, self).__init__(*args, **kwargs)
        self.setupUi(self)        
        self.menubar = QtWidgets.QMenuBar(self)        
        self.options_menu = self.menubar.addMenu('Freeze')
        self.refresh_menu = self.menubar.addMenu('Refresh')
        # Freeze options actions
        self.animlayer_action = QtWidgets.QAction('Add to AnimLayer', self)
        self.animlayer_action.setCheckable(True)
        self.options_menu.addAction(self.animlayer_action)
        self.options_menu.addSeparator()
        self.freeze_action_group = QtWidgets.QActionGroup(self.options_menu)

        self.camera_space_action = QtWidgets.QAction('Freeze in Camera Space',
                                                     self)
        self.camera_space_action.setCheckable(True)
        self.options_menu.addAction(self.camera_space_action)
        self.camera_space_action.setActionGroup(self.freeze_action_group)

        self.world_space_action = QtWidgets.QAction('Freeze in World Space',
                                                    self)
        self.world_space_action.setCheckable(True)
        self.world_space_action.setChecked(True)
        self.options_menu.addAction(self.world_space_action)
        self.world_space_action.setActionGroup(self.freeze_action_group)
        # Refresh action
        self.refresh_action = QtWidgets.QAction('Refresh Rigs List', self)
        self.refresh_menu.addAction(self.refresh_action)
        # Set menubar        
        self.gridLayout.setMenuBar(self.menubar)        
        # Help menu
        help_menu = QtWidgets.QMenu('Help', self.menubar)
        commonmenus.create_help_menu_items(help_menu, tool_help_func=_open_help)
        # Add menus        
        self.menubar.addMenu(self.options_menu)
        self.menubar.addMenu(self.refresh_menu)
        self.menubar.addMenu(help_menu)        

        self.create_connections()
        self.refresh_rigsList()       
        self.populate_ui()        
    def contextMenuEvent(self, event):
        LOG.debug('Attribute TreeView Context Menu Event: %r', event)
        menu = QtWidgets.QMenu(self)

        label = 'Edit Details...'
        edit_act = QtWidgets.QAction(label, self)
        edit_act.triggered.connect(self.set_details_selected_attributes)

        label = 'Lock Attributes'
        lock_act = QtWidgets.QAction(label, self)
        lock_act.triggered.connect(self.lock_selected_attributes)

        label = 'Unlock Attributes'
        unlock_act = QtWidgets.QAction(label, self)
        unlock_act.triggered.connect(self.unlock_selected_attributes)

        label = 'Set Keyframe'
        set_key_act = QtWidgets.QAction(label, self)
        set_key_act.triggered.connect(self.set_keyframe_on_selected_attributes)

        label = 'Delete Keyframe'
        delete_key_current_frame_act = QtWidgets.QAction(label, self)
        delete_key_current_frame_act.triggered.connect(
            self.delete_keyframe_current_frame_on_selected_attributes)

        label = 'Delete Keyframes (Timeline)'
        delete_key_all_frames_act = QtWidgets.QAction(label, self)
        delete_key_all_frames_act.triggered.connect(
            self.delete_keyframe_all_frames_on_selected_attributes)

        label = 'Delete Static Channels'
        delete_static_keys_act = QtWidgets.QAction(label, self)
        delete_static_keys_act.triggered.connect(
            self.delete_static_channel_on_selected_attributes)

        label = 'Break Connections'
        break_conn_act = QtWidgets.QAction(label, self)
        break_conn_act.triggered.connect(
            self.break_connections_on_selected_attributes)

        label = 'Bake Attributes'
        bake_attr_act = QtWidgets.QAction(label, self)
        bake_attr_act.triggered.connect(self.bake_selected_attributes)

        label = 'Reset Values'
        reset_values_act = QtWidgets.QAction(label, self)
        reset_values_act.triggered.connect(
            self.reset_values_on_selected_attributes)

        menu.addAction(edit_act)
        menu.addSeparator()
        menu.addAction(set_key_act)
        menu.addSeparator()
        menu.addAction(delete_key_current_frame_act)
        menu.addAction(delete_key_all_frames_act)
        menu.addAction(delete_static_keys_act)
        menu.addSeparator()
        menu.addAction(break_conn_act)
        menu.addAction(bake_attr_act)
        menu.addAction(reset_values_act)
        menu.addSeparator()
        menu.addAction(lock_act)
        menu.addAction(unlock_act)
        menu.exec_(event.globalPos())
        return
Ejemplo n.º 15
0
    def setupUi(self, parent):
        self.transform_icon = QtGui.QIcon(':transform.svg')

        # Main layout
        self.gridLayout = QtWidgets.QGridLayout(parent)

        # Menu
        self.menu_bar = QtWidgets.QMenuBar()
        self.options_menu = self.menu_bar.addMenu('Freeze')
        self.refresh_menu = self.menu_bar.addMenu('Refresh')

        # Freeze options actions
        self.animlayer_action = QtWidgets.QAction('Add to AnimLayer', self)
        self.animlayer_action.setCheckable(True)
        self.options_menu.addAction(self.animlayer_action)

        self.options_menu.addSeparator()

        self.freeze_action_group = QtWidgets.QActionGroup(self)

        self.camera_space_action = QtWidgets.QAction('Freeze in Camera Space',
                                                     self)
        self.camera_space_action.setCheckable(True)
        self.options_menu.addAction(self.camera_space_action)
        self.camera_space_action.setActionGroup(self.freeze_action_group)

        self.world_space_action = QtWidgets.QAction('Freeze in World Space',
                                                    self)
        self.world_space_action.setCheckable(True)
        self.world_space_action.setChecked(True)
        self.options_menu.addAction(self.world_space_action)
        self.world_space_action.setActionGroup(self.freeze_action_group)

        # Refresh action
        self.refresh_action = QtWidgets.QAction('Refresh Rigs list', self)
        self.refresh_menu.addAction(self.refresh_action)

        self.gridLayout.setMenuBar(self.menu_bar)

        spacerItem = QtWidgets.QSpacerItem(5, 17,
                                           QtWidgets.QSizePolicy.Expanding,
                                           QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem, 0, 0, 1, 1)

        # Full bake radio button
        self.full_bake_rdo_btn = QtWidgets.QRadioButton()
        self.gridLayout.addWidget(self.full_bake_rdo_btn, 0, 1, 1, 1)

        spacerItem1 = QtWidgets.QSpacerItem(5, 17,
                                            QtWidgets.QSizePolicy.Expanding,
                                            QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem1, 0, 2, 1, 1)

        # Smart bake radio button
        self.smart_bake_rdo_btn = QtWidgets.QRadioButton()
        self.smart_bake_rdo_btn.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.smart_bake_rdo_btn.setAutoFillBackground(False)
        self.smart_bake_rdo_btn.setChecked(True)
        self.gridLayout.addWidget(self.smart_bake_rdo_btn, 0, 3, 1, 1)

        spacerItem2 = QtWidgets.QSpacerItem(5, 10,
                                            QtWidgets.QSizePolicy.Expanding,
                                            QtWidgets.QSizePolicy.Minimum)
        self.gridLayout.addItem(spacerItem2, 0, 4, 1, 1)

        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()

        # Rigs label
        self.rigs_label = QtWidgets.QLabel()
        self.horizontalLayout_2.addWidget(self.rigs_label)

        # Rigs list
        self.rigs_list = QtWidgets.QTreeWidget()
        self.rigs_list.setFocusPolicy(QtCore.Qt.NoFocus)
        self.rigs_list.setSelectionMode(
            QtWidgets.QAbstractItemView.ExtendedSelection)
        self.rigs_list.setSelectionBehavior(
            QtWidgets.QAbstractItemView.SelectRows)
        self.rigs_list.setIndentation(15)
        self.rigs_list.setHeaderHidden(True)
        self.horizontalLayout_2.addWidget(self.rigs_list)
        self.gridLayout.addLayout(self.horizontalLayout_2, 2, 0, 1, 5)

        self.horizontalLayout = QtWidgets.QHBoxLayout()

        # Name label
        self.name_label = QtWidgets.QLabel()
        self.horizontalLayout.addWidget(self.name_label)

        # Name line edit
        self.name_text = QtWidgets.QLineEdit()
        self.name_text.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.horizontalLayout.addWidget(self.name_text)

        self.gridLayout.addLayout(self.horizontalLayout, 3, 0, 1, 5)

        # Widget labels
        self.full_bake_rdo_btn.setText('Full bake')
        self.smart_bake_rdo_btn.setText('Smart bake')
        self.rigs_label.setText('Rigs')
        self.name_label.setText('Name')

        self.context_menu = QtWidgets.QMenu()

        self.create_rig_action = QtWidgets.QAction('Create Screen-Space Rig',
                                                   self)
        self.context_menu.addAction(self.create_rig_action)

        self.create_freeze_rig_action = QtWidgets.QAction(
            'Create Freeze Rig', self)
        self.context_menu.addAction(self.create_freeze_rig_action)

        self.context_menu.addSeparator()

        self.match_rig_action = QtWidgets.QAction('Match Screen Z-Depth', self)
        self.context_menu.addAction(self.match_rig_action)

        self.context_menu.addSeparator()

        self.bake_rig_action = QtWidgets.QAction('Bake Rig', self)
        self.context_menu.addAction(self.bake_rig_action)

        self.delete_rig_action = QtWidgets.QAction('Delete Rig', self)
        self.context_menu.addAction(self.delete_rig_action)

        self.context_menu.addSeparator()

        self.select_action = QtWidgets.QAction('Select in Outliner', self)
        self.context_menu.addAction(self.select_action)
        return
Ejemplo n.º 16
0
 def createItem(self, name):
     item = QtWidgets.QTreeWidgetItem([name])
     self.addChildren(item)
     item.setIcon(0, self.transform_icon)
     return item
Ejemplo n.º 17
0
 def create_item(self, name):
     item = QtWidgets.QTreeWidgetItem([name])
     self.add_children(item)
     self.transform_icon = QtGui.QIcon(':transform.svg')
     item.setIcon(0, self.transform_icon)
     return item
Ejemplo n.º 18
0
def _run_tool(window_parent, save_scene, what_to_delete_dict):
    assert isinstance(save_scene, bool)
    assert isinstance(what_to_delete_dict, dict)
    found_nodes_map, unknown_node_found = tool.filter_nodes(
        what_to_delete_dict)

    marker_nodes = found_nodes_map.get('markers', [])
    bundle_nodes = found_nodes_map.get('bundles', [])
    mkr_group_nodes = found_nodes_map.get('marker_groups', [])
    collection_nodes = found_nodes_map.get('collections', [])
    other_nodes = found_nodes_map.get('other_nodes', [])

    nodes_to_delete = []
    for key in found_nodes_map:
        nodes_to_delete += found_nodes_map[key]
    # Remove non-unique nodes.
    nodes_to_delete = list(sorted(set(nodes_to_delete)))

    title = const.WINDOW_TITLE
    if len(nodes_to_delete) == 0:
        msg = ('No nodes found, '
               'please choose different options in the window.\n')
        QtWidgets.QMessageBox.warning(window_parent, title, msg)
        return False

    details = _generate_details_text(marker_nodes=marker_nodes,
                                     bundle_nodes=bundle_nodes,
                                     mkr_group_nodes=mkr_group_nodes,
                                     collection_nodes=collection_nodes,
                                     other_nodes=other_nodes)

    msg = _generate_message_text(unknown_node_found=unknown_node_found,
                                 nodes_to_delete=nodes_to_delete,
                                 marker_nodes=marker_nodes,
                                 bundle_nodes=bundle_nodes,
                                 mkr_group_nodes=mkr_group_nodes,
                                 collection_nodes=collection_nodes,
                                 other_nodes=other_nodes)

    inform_text = 'Are you sure you want to delete?'
    dialog = QtWidgets.QMessageBox(window_parent, )
    dialog.setWindowTitle(title)
    dialog.setIcon(QtWidgets.QMessageBox.Question)
    dialog.setText(msg)
    dialog.setInformativeText(inform_text)
    dialog.setDetailedText(details)
    clicked_button = dialog.exec_()
    if clicked_button == QtWidgets.QMessageBox.No:
        return False

    if save_scene is True:
        maya.cmds.file(save=True)

    undo_id = 'removesolvernodes: '
    undo_id += str(datetime.datetime.isoformat(datetime.datetime.now()))
    undo_id += ' '
    undo_id += str(uuid.uuid4())
    with tools_utils.tool_context(use_undo_chunk=True,
                                  undo_chunk_name=undo_id,
                                  restore_current_frame=True):
        tool.delete_nodes(nodes_to_delete)
    return True
    def addMenuBarContents(self, menubar):
        # File Menu
        file_menu = QtWidgets.QMenu('File', menubar)

        # New Collection
        label = 'New Collection'
        tooltip = 'Create a new Collection node.'
        action = QtWidgets.QAction(label, file_menu)
        action.setStatusTip(tooltip)
        action.triggered.connect(partial(self.createNewCollectionNodeCB))
        file_menu.addAction(action)

        # Rename Collection
        label = 'Rename Collection...'
        tooltip = 'Rename a Collection node.'
        action = QtWidgets.QAction(label, file_menu)
        action.setStatusTip(tooltip)
        action.triggered.connect(partial(self.renameCollectionNodeCB))
        file_menu.addAction(action)

        file_menu.addSeparator()

        # Remove Collection
        label = 'Remove Collection...'
        tooltip = 'Remove a Collection node.'
        action = QtWidgets.QAction(label, file_menu)
        action.setStatusTip(tooltip)
        action.triggered.connect(partial(self.removeCollectionNodeCB))
        file_menu.addAction(action)

        file_menu.addSeparator()

        # Close Window
        label = 'Close Window'
        tooltip = 'Close the mmSolver window.'
        action = QtWidgets.QAction(label, file_menu)
        action.setStatusTip(tooltip)
        action.triggered.connect(partial(self.close))
        file_menu.addAction(action)

        menubar.addMenu(file_menu)

        # Edit Menu
        edit_menu = QtWidgets.QMenu('Edit', menubar)
        edit_menu.setTearOffEnabled(True)

        if Qt.IsPySide2 or Qt.IsPyQt5:
            edit_menu.addSection('Undo / Redo')

        # Undo
        label = 'Undo last command (with disabled viewport)'
        tooltip = ('Undo the Maya scene state, '
                   'without updating the viewport or solver UI')
        action = QtWidgets.QAction(label, edit_menu)
        action.setStatusTip(tooltip)
        action.triggered.connect(self.undoTriggeredCB)
        edit_menu.addAction(action)

        # Redo
        label = 'Redo last command (with disabled viewport)'
        tooltip = ('Redo the Maya scene state, '
                   'without updating the viewport or solver UI')
        action = QtWidgets.QAction(label, edit_menu)
        action.setStatusTip(tooltip)
        action.triggered.connect(self.redoTriggeredCB)
        edit_menu.addAction(action)

        if Qt.IsPySide2 or Qt.IsPyQt5:
            edit_menu.addSection('Window Update')

        # Auto Update Solver Validation
        label = 'Auto-Update Solver Validation'
        tooltip = 'Auto-update details of the solver parameter/error numbers.'
        value = lib_state.get_auto_update_solver_validation_state()
        action = QtWidgets.QAction(label, edit_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            self.subForm.solver_settings.autoUpdateSolverValidationChanged)
        edit_menu.addAction(action)

        if Qt.IsPySide2 or Qt.IsPyQt5:
            edit_menu.addSection('Solver Execution')

        # Pre-Solve Force Evaluation
        label = 'Pre-Solve Force Evaluation'
        tooltip = ('Before starting a solve, '
                   'update the scene to force an evaluation.')
        pre_solve_force_eval = lib_state.get_pre_solve_force_eval_state()
        action = QtWidgets.QAction(label, edit_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(pre_solve_force_eval)
        action.toggled.connect(type(self).preSolveForceEvalActionToggledCB)
        edit_menu.addAction(action)

        # Refresh Viewport During Solve
        label = 'Refresh Viewport'
        tooltip = 'Refresh the viewport while Solving.'
        refresh_value = lib_state.get_refresh_viewport_state()
        action = QtWidgets.QAction(label, edit_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(refresh_value)
        action.toggled.connect(type(self).refreshActionToggledCB)
        edit_menu.addAction(action)

        # Force DG evaluation.
        label = 'Force DG Update'
        tooltip = 'Force Maya DG Evaluation while solving.'
        force_dg_update_value = lib_state.get_force_dg_update_state()
        action = QtWidgets.QAction(label, edit_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(force_dg_update_value)
        action.toggled.connect(type(self).forceDgUpdateActionToggledCB)
        edit_menu.addAction(action)

        menubar.addMenu(edit_menu)

        # View Menu
        view_menu = QtWidgets.QMenu('View', menubar)
        view_menu.setTearOffEnabled(True)

        if Qt.IsPySide2 or Qt.IsPyQt5:
            view_menu.addSection('Input Object Display')

        # Display Object Weight
        label = 'Weight Column'
        tooltip = 'Display Object weight column'
        value = lib_state.get_display_object_weight_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            self.subForm.object_browser.displayWeightColumnChanged)
        view_menu.addAction(action)

        # Display Object Frame Deviation
        label = 'Frame Deviation'
        tooltip = 'Display per-frame deviation for each Marker/Camera.'
        value = lib_state.get_display_object_frame_deviation_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            self.subForm.object_browser.displayFrameDeviationColumnChanged)
        view_menu.addAction(action)

        # Display Object Average Deviation
        label = 'Average Deviation'
        tooltip = 'Display average deviation column'
        value = lib_state.get_display_object_average_deviation_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            self.subForm.object_browser.displayAverageDeviationColumnChanged)
        view_menu.addAction(action)

        # Display Object Maximum Deviation
        label = 'Maximum Deviation'
        tooltip = 'Display maximum deviation column'
        value = lib_state.get_display_object_maximum_deviation_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            self.subForm.object_browser.displayMaximumDeviationColumnChanged)
        view_menu.addAction(action)

        if Qt.IsPySide2 or Qt.IsPyQt5:
            view_menu.addSection('Output Attribute Display')

        # Display Attribute State
        label = 'Display Attribute State'
        tooltip = 'Display Attribute State column'
        value = lib_state.get_display_attribute_state_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            self.subForm.attribute_browser.displayStateColumnChanged)
        view_menu.addAction(action)

        # Display Attribute Smoothness
        label = 'Display Attribute Smoothness'
        tooltip = 'Display Attribute Smoothness columns'
        value = lib_state.get_display_attribute_smoothness_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            self.subForm.attribute_browser.displaySmoothnessColumnChanged)
        view_menu.addAction(action)

        # Display Attribute Stiffness
        label = 'Display Attribute Stiffness'
        tooltip = 'Display Attribute Stiffness columns'
        value = lib_state.get_display_attribute_stiffness_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            self.subForm.attribute_browser.displayStiffnessColumnChanged)
        view_menu.addAction(action)

        # Display Attribute Min/Max
        label = 'Display Attribute Min/Max'
        tooltip = 'Display Attribute Minimum and Maximum columns'
        value = lib_state.get_display_attribute_min_max_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            self.subForm.attribute_browser.displayMinMaxColumnChanged)
        view_menu.addAction(action)

        if Qt.IsPySide2 or Qt.IsPyQt5:
            view_menu.addSection('During Solve')

        # Display the Image Planes while solving.
        #
        # TODO: Add other object types to show/hide while solving,
        #  such as camera, nurbsCurves, nurbsSurfaces, and locators.
        label = 'Display Image Planes'
        tooltip = 'Display Image Planes while solving.'
        value = lib_state.get_display_image_plane_while_solving_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            type(self).displayImagePlaneWhileSolvingActionToggledCB)
        view_menu.addAction(action)

        # Display the Meshes while solving.
        label = 'Display Meshes'
        tooltip = 'Display Meshes while solving.'
        value = lib_state.get_display_meshes_while_solving_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(value)
        action.toggled.connect(
            type(self).displayMeshesWhileSolvingActionToggledCB)
        view_menu.addAction(action)

        # Isolate Objects while solving
        label = 'Isolate Objects'
        tooltip = 'Isolate visibility of all Markers and Bundles while solving.'
        isolate_value = lib_state.get_isolate_object_while_solving_state()
        action = QtWidgets.QAction(label, view_menu)
        action.setStatusTip(tooltip)
        action.setCheckable(True)
        action.setChecked(isolate_value)
        action.toggled.connect(
            type(self).isolateObjectWhileSolvingActionToggledCB)
        view_menu.addAction(action)

        menubar.addMenu(view_menu)

        # Log Menu
        # This menu depicts a radio button allowing the user to choose
        # how much information is returned to the console (the logging
        # level).
        log_menu = QtWidgets.QMenu('Log', menubar)

        # Errors
        label = 'Errors'
        tooltip = 'Send Errors to the log.'
        logErrorAction = QtWidgets.QAction(label, log_menu)
        logErrorAction.setStatusTip(tooltip)
        logErrorAction.setCheckable(True)
        logErrorAction.triggered.connect(partial(self.logErrorCB))
        log_menu.addAction(logErrorAction)

        # Warnings
        label = 'Warnings'
        tooltip = 'Send Warnings to the log.'
        logWarningAction = QtWidgets.QAction(label, log_menu)
        logWarningAction.setStatusTip(tooltip)
        logWarningAction.setCheckable(True)
        logWarningAction.triggered.connect(partial(self.logWarningCB))
        log_menu.addAction(logWarningAction)

        # Information
        label = 'Info'
        tooltip = 'Send Information to the log.'
        logInfoAction = QtWidgets.QAction(label, log_menu)
        logInfoAction.setStatusTip(tooltip)
        logInfoAction.setCheckable(True)
        logInfoAction.triggered.connect(partial(self.logInfoCB))
        log_menu.addAction(logInfoAction)

        # Verbose
        label = 'Verbose'
        tooltip = 'Send Verboses to the log.'
        logVerboseAction = QtWidgets.QAction(label, log_menu)
        logVerboseAction.setStatusTip(tooltip)
        logVerboseAction.setCheckable(True)
        logVerboseAction.triggered.connect(partial(self.logVerboseCB))
        log_menu.addAction(logVerboseAction)

        # Debug
        label = 'Debug'
        tooltip = 'Send Debug messages to the log.'
        logDebugAction = QtWidgets.QAction(label, log_menu)
        logDebugAction.setStatusTip(tooltip)
        logDebugAction.setCheckable(True)
        logDebugAction.triggered.connect(partial(self.logDebugCB))
        log_menu.addAction(logDebugAction)

        # 'Radio' button for logging levels
        log_actionGroup = QtWidgets.QActionGroup(log_menu)
        log_actionGroup.addAction(logErrorAction)
        log_actionGroup.addAction(logWarningAction)
        log_actionGroup.addAction(logInfoAction)
        log_actionGroup.addAction(logVerboseAction)
        log_actionGroup.addAction(logDebugAction)

        log_level = lib_state.get_log_level()
        if log_level == const.LOG_LEVEL_ERROR:
            logErrorAction.setChecked(True)
        elif log_level == const.LOG_LEVEL_WARNING:
            logWarningAction.setChecked(True)
        elif log_level == const.LOG_LEVEL_INFO:
            logInfoAction.setChecked(True)
        elif log_level == const.LOG_LEVEL_VERBOSE:
            logVerboseAction.setChecked(True)
        elif log_level == const.LOG_LEVEL_DEBUG:
            logDebugAction.setChecked(True)
        else:
            LOG.warning('Invalid log level given: %r' % log_level)

        menubar.addMenu(log_menu)

        # Help Menu
        help_menu = QtWidgets.QMenu('Help', menubar)
        commonmenus.create_help_menu_items(help_menu,
                                           tool_help_func=_open_help)
        menubar.addMenu(help_menu)
        return
 def add_menus(self, menubar):
     help_menu = QtWidgets.QMenu('Help', menubar)
     commonmenus.create_help_menu_items(help_menu,
                                        tool_help_func=_open_help)
     menubar.addMenu(help_menu)