# -*- coding: utf-8 -*- """ :author: Jeremy Ernst :description: This module contains a class that builds a widget for editing a component's settings, like number of joints, or prefix/suffix, etc. """ import os from functools import partial from artv2.third_party.Qt import QtWidgets, QtCore, QtGui import artv2.utilities.general_utilities as utils import artv2.utilities.component_utilities as component_utils import artv2.utilities.interface_utilities as interface_utils import artv2.tools.rigging.rig_builder.parent_list_widget as parent_list import artv2.tools.system.logger.output_logger as logger import pymel.core as pm class ComponentSettingsWidget(QtWidgets.QFrame): """ This class creates a widget that is used to edit a component's settings, like number of joint, prefix/suffix, parent, etc. :param metanode: string name of the component's network node that contains the component's settings. :param layout: the layout this widget will be added to. :param list_item: the QListWidgetItem that was clicked on to invoke the creation of this widget. :param list_label: the label of the QListWidgetItem that was clicked on to invoke the creation of this widget. :param parent: an instance of the InstalledComponentsWidget that is this widget's parent. .. figure:: /images/component_settings_widget.png :width: 213px :align: center :height: 468px :figclass: align-center """ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def __init__(self, metanode, layout, list_item, list_label, parent=None): super(ComponentSettingsWidget, self).__init__(parent) self.logger = logger.OutputLogger(self.__class__.__name__) # declare variables self.metanode = pm.PyNode(metanode) self.parent_layout = layout self.list_label = list_label self.list_item = list_item self.icon_path = utils.return_settings()[2] # build base of widget self.main_layout = QtWidgets.QVBoxLayout(self) self.setLayout(self.main_layout) self.main_layout.setSpacing(3) self.parent_layout.addWidget(self) self.scroll_contents = QtWidgets.QFrame() self.scroll_contents.setObjectName("light") self.scroll_contents.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.scroll_area = QtWidgets.QScrollArea() self.main_layout.addWidget(self.scroll_area) self.scroll_area.setWidgetResizable(True) self.scroll_area.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.scroll_area.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.scroll_area.setWidget(self.scroll_contents) self.contents_layout = QtWidgets.QVBoxLayout(self.scroll_contents) # populate widget self._build_interface() # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _build_interface(self): inst = component_utils.get_component_instance(self.metanode) properties = utils.get_class_properties(inst) self.header = QtWidgets.QLabel("{0} Settings:".format(inst.network_node.componentName.get())) line = QtWidgets.QFrame() line.setFrameShape(QtWidgets.QFrame.HLine) line.setFrameShadow(QtWidgets.QFrame.Sunken) self.contents_layout.addWidget(self.header) self.contents_layout.addWidget(line) self.metanode_label = QtWidgets.QLabel("metanode: {0}".format(inst.network_node.nodeName())) self.metanode_label.setEnabled(False) self.contents_layout.addWidget(self.metanode_label) prefix_layout = QtWidgets.QHBoxLayout() self.contents_layout.addLayout(prefix_layout) prefix_label = QtWidgets.QLabel("Prefix: ") prefix_label.setMinimumWidth(interface_utils.scale_by_dpi(40)) prefix_label.setMaximumWidth(interface_utils.scale_by_dpi(40)) self.prefix_field = QtWidgets.QLineEdit() self.prefix_field.returnPressed.connect(self._set_prefix) prefix_layout.addWidget(prefix_label) prefix_layout.addWidget(self.prefix_field) suffix_layout = QtWidgets.QHBoxLayout() self.contents_layout.addLayout(suffix_layout) suffix_label = QtWidgets.QLabel("Suffix: ") suffix_label.setMinimumWidth(interface_utils.scale_by_dpi(40)) suffix_label.setMaximumWidth(interface_utils.scale_by_dpi(40)) self.suffix_field = QtWidgets.QLineEdit() self.suffix_field.returnPressed.connect(self._set_suffix) suffix_layout.addWidget(suffix_label) suffix_layout.addWidget(self.suffix_field) parent_layout = QtWidgets.QHBoxLayout() self.contents_layout.addLayout(parent_layout) parent_label = QtWidgets.QLabel("Parent: ") parent_label.setMinimumWidth(interface_utils.scale_by_dpi(40)) parent_label.setMaximumWidth(interface_utils.scale_by_dpi(40)) self.parent_field = QtWidgets.QLineEdit() self.parent_field.editingFinished.connect(self._set_parent) self.parent_field.setReadOnly(True) parent_button = QtWidgets.QPushButton() parent_button.setMinimumWidth(interface_utils.scale_by_dpi(25)) parent_button.setMaximumWidth(interface_utils.scale_by_dpi(25)) parent_button.setMinimumHeight(interface_utils.scale_by_dpi(25)) parent_button.setMaximumHeight(interface_utils.scale_by_dpi(25)) icon = QtGui.QIcon(os.path.join(self.icon_path, "general/search.png")) parent_button.setIconSize(QtCore.QSize(21, 21)) parent_button.setIcon(icon) parent_button.clicked.connect(self._launch_parent_list) parent_layout.addWidget(parent_label) parent_layout.addWidget(self.parent_field) parent_layout.addWidget(parent_button) mirror_layout = QtWidgets.QHBoxLayout() self.contents_layout.addLayout(mirror_layout) mirror_label = QtWidgets.QLabel("Mirror: ") mirror_label.setMinimumWidth(interface_utils.scale_by_dpi(40)) mirror_label.setMaximumWidth(interface_utils.scale_by_dpi(40)) self.mirror_field = QtWidgets.QComboBox() mirror_layout.addWidget(mirror_label) mirror_layout.addWidget(self.mirror_field) self._find_components() self.mirror_field.currentIndexChanged.connect(self._set_mirror) separator = QtWidgets.QFrame() separator.setFrameShape(QtWidgets.QFrame.HLine) separator.setFrameShadow(QtWidgets.QFrame.Sunken) self.contents_layout.addWidget(separator) if inst.has_sides: side_layout = QtWidgets.QHBoxLayout() self.contents_layout.addLayout(side_layout) side_label = QtWidgets.QLabel("Side: ") side_label.setMinimumWidth(interface_utils.scale_by_dpi(40)) side_label.setMaximumWidth(interface_utils.scale_by_dpi(40)) self.left_side = QtWidgets.QRadioButton("Left") self.left_side.toggled.connect(self._set_side) self.right_side = QtWidgets.QRadioButton("Right") self.right_side.toggled.connect(self._set_side) side_layout.addWidget(side_label) side_layout.addWidget(self.left_side) side_layout.addWidget(self.right_side) # add widgets for unique component properties self._build_property_widgets(properties) # add widgets for overriding joint names self.joint_layout = QtWidgets.QVBoxLayout() self.joint_layout.setSpacing(1) self.contents_layout.addLayout(self.joint_layout) if inst.can_overwrite_names: self._build_joint_widgets(inst) spacer = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.contents_layout.addSpacerItem(spacer) self._populate_fields(inst) del inst # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _build_property_widgets(self, properties): for each in properties: value = properties.get(each) if isinstance(value, bool): checkbox = QtWidgets.QCheckBox(each) checkbox.setChecked(value) checkbox.stateChanged.connect(partial(self._set_property, checkbox, each, value)) self.contents_layout.addWidget(checkbox) if isinstance(value, float): layout = QtWidgets.QHBoxLayout() self.contents_layout.addLayout(layout) label = QtWidgets.QLabel("{0}: ".format(each)) layout.addWidget(label) validator = QtGui.QIntValidator() input_field = QtWidgets.QLineEdit() input_field.setValidator(validator) input_field.setText(str(int(value))) input_field.setMinimumWidth(interface_utils.scale_by_dpi(50)) input_field.setMaximumWidth(interface_utils.scale_by_dpi(50)) input_field.returnPressed.connect(partial(self._set_property, input_field, each, value)) layout.addWidget(input_field) end_separator = QtWidgets.QFrame() end_separator.setFrameShape(QtWidgets.QFrame.HLine) end_separator.setFrameShadow(QtWidgets.QFrame.Sunken) self.contents_layout.addWidget(end_separator) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _build_joint_widgets(self, inst): group_box = QtWidgets.QGroupBox("Override Joint Names:") group_box.setCheckable(True) self.joint_layout.addWidget(group_box) group_layout = QtWidgets.QVBoxLayout(group_box) group_layout.setSpacing(1) joint_data = component_utils.get_joint_labels(inst.network_node) for joint in joint_data: field = QtWidgets.QLineEdit(joint_data.get(joint)[0]) field.returnPressed.connect(partial(self._set_joint_name, field, joint, joint_data)) group_layout. addWidget(field) group_box.toggled.connect(partial(interface_utils.toggle_group, group_box)) group_box.setChecked(False) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _populate_fields(self, inst): self.prefix_field.setText(inst.prefix) self.suffix_field.setText(inst.suffix) self.parent_field.setText(inst.parent) if inst.has_sides: side = inst.network_node.side.get() if side == 0: self.left_side.setChecked(True) if side == 1: self.right_side.setChecked(True) current_mirror = inst.network_node.mirror_component.connections() if current_mirror: mirror_name = current_mirror[0].componentName.get() index = self.mirror_field.findText(mirror_name) self.mirror_field.setCurrentIndex(index) else: index = self.mirror_field.findText("None") self.mirror_field.setCurrentIndex(index) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _find_components(self): components = component_utils.get_all_component_names() index = 0 for each in components: self.mirror_field.addItem(each) self.mirror_field.setItemData(index, components.get(each).nodeName()) index += 1 self.mirror_field.addItem("None") # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _launch_parent_list(self): widget = parent_list.ChooseParentList(self) pos = QtGui.QCursor.pos() widget.move(pos.x() + 10, pos.y() + 10) widget.exec_() # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _set_prefix(self): inst = component_utils.get_component_instance(self.metanode) self.logger.interface("{0}._set_prefix: Setting prefix to {2} on {1}" "".format(self.__class__.__name__, self.metanode.componentName.get(), self.prefix_field.text())) setattr(inst, "prefix", self.prefix_field.text()) # refresh value in case value entered was invalid. current_value = getattr(inst, "prefix") self.prefix_field.setText(current_value) self.list_label.setText(inst.network_node.componentName.get()) self.list_item.setData(QtCore.Qt.UserRole, inst.network_node.nodeName()) self.header.setText("{0} Settings:".format(inst.network_node.componentName.get())) self.metanode_label.setText("metanode: {0}".format(inst.network_node.nodeName())) # refresh the joint naming widget interface_utils.clear_layout(self.joint_layout) self._build_joint_widgets(inst) del inst # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _set_suffix(self): inst = component_utils.get_component_instance(self.metanode) self.logger.interface("{0}._set_suffix: Setting suffix to {2} on {1}" "".format(self.__class__.__name__, self.metanode.componentName.get(), self.suffix_field.text())) setattr(inst, "suffix", self.suffix_field.text()) # refresh value in case value entered was invalid. current_value = getattr(inst, "suffix") self.suffix_field.setText(current_value) self.list_label.setText(inst.network_node.componentName.get()) self.list_item.setData(QtCore.Qt.UserRole, inst.network_node.nodeName()) self.header.setText("{0} Settings:".format(inst.network_node.componentName.get())) self.metanode_label.setText("metanode: {0}".format(inst.network_node.nodeName())) # refresh the joint naming widget interface_utils.clear_layout(self.joint_layout) self._build_joint_widgets(inst) del inst # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _set_parent(self): inst = component_utils.get_component_instance(self.metanode) self.logger.interface("{0}._set_parent: Setting parent to {2} on {1}" "".format(self.__class__.__name__, self.metanode.componentName.get(), self.parent_field.text())) setattr(inst, "parent", self.parent_field.text()) # refresh value in case value entered was invalid. current_value = getattr(inst, "parent") self.parent_field.setText(current_value) del inst # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _set_mirror(self): selected = self.mirror_field.currentIndex() item_data = self.mirror_field.itemData(selected) if item_data is not None: network_node = pm.PyNode(item_data) else: network_node = None inst = component_utils.get_component_instance(self.metanode) self.logger.interface("{0}._set_mirror: Setting mirror to {2} on {1}" "".format(self.__class__.__name__, self.metanode.componentName.get(), item_data)) inst.set_mirror(network_node) # refresh value in case value entered was invalid. current_mirror = inst.network_node.mirror_component.connections() if current_mirror: mirror_name = current_mirror[0].componentName.get() index = self.mirror_field.findText(mirror_name) self.mirror_field.setCurrentIndex(index) else: index = self.mirror_field.findText("None") self.mirror_field.setCurrentIndex(index) del inst # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _set_side(self): inst = component_utils.get_component_instance(self.metanode) left = self.left_side.isChecked() right = self.right_side.isChecked() if left: self.logger.interface("{0}._set_side: Setting side to left on {1}" "".format(self.__class__.__name__, self.metanode.componentName.get())) inst.set_side("left") if right: self.logger.interface("{0}._set_side: Setting side to right on {1}" "".format(self.__class__.__name__, self.metanode.componentName.get())) inst.set_side("right") del inst # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _set_property(self, widget, property_name, property_type, *args): inst = component_utils.get_component_instance(self.metanode) if isinstance(property_type, bool): value = widget.isChecked() self.logger.interface("{0}._set_property: Setting {1} on {2} to {3}." "".format(self.__class__.__name__, property_name, self.metanode.componentName.get(), value)) setattr(inst, property_name, value) # refresh value in case value entered was invalid. current_value = getattr(inst, property_name) widget.setChecked(current_value) if isinstance(property_type, float): value = int(widget.text()) self.logger.interface("{0}._set_property: Setting {1} on {2} to {3}." "".format(self.__class__.__name__, property_name, self.metanode.componentName.get(), value)) setattr(inst, property_name, value) # refresh value in case value entered was invalid. current_value = getattr(inst, property_name) widget.setText(str(int(current_value))) if inst.can_overwrite_names: interface_utils.clear_layout(self.joint_layout) self._build_joint_widgets(inst) del inst # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def _set_joint_name(self, widget, joint, joint_data): inst = component_utils.get_component_instance(self.metanode) self.logger.interface("{0}._set_joint_name: Setting joint name for {1} ({2}) to {3}" "".format(self.__class__.__name__, joint, self.metanode.componentName.get(), widget.text())) renamed = inst.rename_joint(widget.text(), joint_data.get(joint)[0], joint_data.get(joint)[2]) if not renamed: widget.setText(joint_data.get(joint)[0]) del inst