Пример #1
0
class BreadcrumbWidget(base.BaseWidget, object):
    """
    Widget that display current location withing a hierarchy
    It allows going back/forward inside a hierarchy
    """
    def __init__(self, separator=None, parent=None):
        super(BreadcrumbWidget, self).__init__(parent=parent)

        current_theme = self.theme()

        separator_color = current_theme.accent_color if current_theme else '#E2AC2C'

        self._separator = separator or "<span style='color:{}'> &#9656; </span>".format(
            separator_color)
        self._separators = list()

        self.setObjectName('BreadcrumbWidget')
        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

    def get_main_layout(self):
        main_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0))
        main_layout.addStretch()

        return main_layout

    def ui(self):
        super(BreadcrumbWidget, self).ui()

        self._button_group = QButtonGroup()

    def set_items(self, data_list):
        """
        Sets the the items of the breadcrumb cleaning old ones
        :param data_list:
        :return:
        """

        for btn in self._button_group.buttons():
            self._button_group.removeButton(btn)
            self.main_layout.removeWidget(btn)
            btn.setVisible(False)
            btn.deleteLater()
        for sep in self._separators:
            self.main_layout.removeWidget(sep)
            sep.setVisible(False)
            sep.deleteLater()
        python.clear_list(self._separators)

        for index, data_dict in enumerate(data_list):
            self.add_item(data_dict, index)

    def add_item(self, data_dict, index=None):
        """
        Adds a new item to the breadcrumb
        :param data_dict: dict
        :param index: int
        """

        btn = buttons.BaseToolButton()
        btn.setText(data_dict.get('text'))
        if data_dict.get('image'):
            btn.image(data_dict.get('image'))
        if data_dict.get('tooltip'):
            btn.setProperty('toolTip', data_dict.get('tooltip'))
        if data_dict.get('clicked'):
            btn.clicked.connect(data_dict.get('clicked'))
        if data_dict.get('text'):
            if data_dict.get('svg') or data_dict.get('icon'):
                btn.text_beside_icon()
            else:
                btn.text_only()
        else:
            btn.icon_only()

        if self._button_group.buttons():
            separator = label.BaseLabel(self._separator).secondary()
            self._separators.append(separator)
            self.main_layout.insertWidget(self.main_layout.count() - 1,
                                          separator)
        self.main_layout.insertWidget(self.main_layout.count() - 1, btn)

        if index is None:
            self._button_group.addButton(btn)
        else:
            self._button_group.addButton(btn, index)

    def set_from_path(self, file_path):
        """
        Creates a proper Breadcrumb list for given path and sets the text
        """

        self._widgets = list()
        file_path = os.path.dirname(file_path)
        folders = path.get_folders_from_path(file_path)
        data_list = list()
        for folder in folders:
            data_list.append({'text': folder})
        self.set_items(data_list)

    def get_breadcumbs(self):
        """
        Returns current list of breadcumb texts
        :return: list(str)
        """

        return [btn.text() for btn in self._button_group.buttons()]
class AlembicManagerView(tool.ArtellaToolWidget, object):

    def __init__(self, project, config, settings, parent):
        super(AlembicManagerView, self).__init__(project=project, config=config, settings=settings, parent=parent)

    def ui(self):
        super(AlembicManagerView, self).ui()

        export_icon = resources.icon('export')
        import_icon = resources.icon('import')

        buttons_layout = layouts.HorizontalLayout(spacing=2, margins=(2, 2, 2, 2))
        self.main_layout.addLayout(buttons_layout)
        self.main_layout.addLayout(dividers.DividerLayout())

        self._exporter_btn = buttons.BaseButton('Exporter', parent=self)
        self._exporter_btn.setIcon(export_icon)
        self._exporter_btn.setMinimumWidth(80)
        self._exporter_btn.setCheckable(True)
        self._importer_btn = buttons.BaseButton('Importer', parent=self)
        self._importer_btn.setIcon(import_icon)
        self._importer_btn.setMinimumWidth(80)
        self._importer_btn.setCheckable(True)
        buttons_layout.addStretch()
        buttons_layout.addWidget(self._exporter_btn)
        buttons_layout.addWidget(self._importer_btn)
        self._importer_btn.setCheckable(True)

        self._buttons_grp = QButtonGroup(self)
        self._buttons_grp.setExclusive(True)
        self._buttons_grp.addButton(self._exporter_btn)
        self._buttons_grp.addButton(self._importer_btn)
        self._exporter_btn.setChecked(True)

        self._stack = stack.SlidingStackedWidget()
        self.main_layout.addWidget(self._stack)

        self._alembic_exporter = exporter.AlembicExporter(project=self.project)
        self._alembic_importer = importer.AlembicImporter(project=self.project)

        self._stack.addWidget(self._alembic_exporter)
        self._stack.addWidget(self._alembic_importer)

    def setup_signals(self):
        self._stack.animFinished.connect(self._on_stack_anim_finished)
        self._exporter_btn.clicked.connect(partial(self._on_slide_stack, 0))
        self._importer_btn.clicked.connect(partial(self._on_slide_stack, 1))
        self._alembic_exporter.showWarning.connect(self._on_show_warning)
        self._alembic_exporter.showOk.connect(self._on_show_ok)
        self._alembic_importer.showOk.connect(self._on_show_ok)

    def _on_slide_stack(self, index):
        """
        Internal callback function that is called when stack needs to change current widget
        :param index: int
        """

        if index == self._stack.currentIndex():
            return

        for btn in self._buttons_grp.buttons():
            btn.setEnabled(False)

        self._stack.slide_in_index(index)

    def _on_stack_anim_finished(self):
        """
        Internal callback function that is called when stack anim finish
        """

        for btn in self._buttons_grp.buttons():
            btn.setEnabled(True)

        if self._stack.currentWidget() == self._alembic_exporter:
            self._alembic_exporter.refresh()

    def _on_show_ok(self, warning_msg):
        """
        Internal callback function that is called when an ok message should be showed
        :param warning_msg: str
        """

        logger.debug(warning_msg)
        self.show_ok_message(warning_msg)

    def _on_show_warning(self, warning_msg):
        """
        Internal callback function that is called when a warning message should be showed
        :param warning_msg: str
        """

        logger.warning(warning_msg)
        self.show_warning_message(warning_msg)
Пример #3
0
class BaseButtonGroup(base.BaseWidget, object):
    def __init__(self, orientation=Qt.Horizontal, parent=None):

        self._orientation = 'horizontal' if orientation == Qt.Horizontal else 'vertical'

        super(BaseButtonGroup, self).__init__(parent=parent)

    def get_main_layout(self):
        main_layout = QBoxLayout(QBoxLayout.LeftToRight if self._orientation ==
                                 'horizontal' else QBoxLayout.TopToBottom)
        main_layout.setContentsMargins(0, 0, 0, 0)

        return main_layout

    def ui(self):
        super(BaseButtonGroup, self).ui()

        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        self._button_group = QButtonGroup()

    @decorators.abstractmethod
    def create_button(self, data_dict):
        """
        Must be implemented in custom button groups
        Creates a new button for this group
        :param data_dict: dict
        :return: new button instance
        """

        raise NotImplementedError(
            'Function create_button for class "{}" is not implemented!'.format(
                self.__class__.__name__))

    def get_button_group(self):
        """
        Returns button group internal object
        :return: QButtonGroup
        """

        return self._button_group

    def clear(self):
        """
        Clears all buttons contained in this group
        """

        for btn in self._button_group.buttons():
            self._button_group.removeButton(btn)
            self.main_layout.removeWidget(btn)
            btn.setVisible(False)
            btn.deleteLater()

    def add_button(self, data_dict, index=None):
        """
        Adds a new button to this group
        :param data_dict: dict
        :param index: int or None
        :return: new added button
        """

        if python.is_string(data_dict):
            data_dict = {'text': data_dict}
        elif isinstance(data_dict, QIcon):
            data_dict = {'icon': data_dict}

        new_btn = self.create_button(data_dict)
        new_btn.setProperty('combine', self._orientation)

        if data_dict.get('text'):
            new_btn.setProperty('text', data_dict.get('text'))
        if data_dict.get('icon'):
            new_btn.setProperty('icon', data_dict.get('icon'))
        if data_dict.get('data'):
            new_btn.setProperty('data', data_dict.get('data'))
        if data_dict.get('checked'):
            new_btn.setProperty('checked', data_dict.get('checked'))
        if data_dict.get('shortcut'):
            new_btn.setProperty('shortcut', data_dict.get('shortcut'))
        if data_dict.get('tooltip'):
            new_btn.setProperty('toolTip', data_dict.get('tooltip'))
        if data_dict.get('clicked'):
            new_btn.clicked.connect(data_dict.get('clicked'))
        if data_dict.get('toggled'):
            new_btn.toggled.connect(data_dict.get('toggled'))

        if index is None:
            self._button_group.addButton(new_btn)
        else:
            self._button_group.addButton(new_btn, index)

        if self.main_layout.count() == 0:
            new_btn.setChecked(True)

        self.main_layout.insertWidget(self.main_layout.count(), new_btn)

        return new_btn

    def set_button_list(self, button_list):
        """
        Empties group and add all buttons given in the list of buttons
        :param button_list: list(dict)
        """

        self.clear()

        for index, data_dict in enumerate(button_list):
            new_btn = self.add_button(data_dict=data_dict, index=index)
            if index == 0:
                new_btn.setProperty('position', 'left')
            elif index == len(button_list) - 1:
                new_btn.setProperty('position', 'right')
            else:
                new_btn.setProperty('position', 'center')
Пример #4
0
class RenamerView(base.BaseWidget, object):
    def __init__(self, model, controller, parent=None):

        self._model = model
        self._controller = controller

        super(RenamerView, self).__init__(parent=parent)

        self.refresh()

    @property
    def model(self):
        return self._model

    @property
    def controller(self):
        return self._controller

    def ui(self):
        super(RenamerView, self).ui()

        top_layout = layouts.HorizontalLayout(spacing=2, margins=(2, 2, 2, 2))
        top_layout.setAlignment(Qt.AlignLeft)
        self._buttons_grp = QButtonGroup(self)
        self._buttons_grp.setExclusive(True)
        self.main_layout.addLayout(top_layout)
        self.main_layout.addLayout(dividers.DividerLayout())

        self._categories_layout = layouts.HorizontalLayout(spacing=2,
                                                           margins=(2, 2, 2,
                                                                    2))
        self._categories_layout.setAlignment(Qt.AlignLeft)

        selection_layout = layouts.HorizontalLayout(spacing=2,
                                                    margins=(4, 0, 4, 0))
        top_layout.addLayout(selection_layout)

        self._all_radio = buttons.BaseRadioButton('All', parent=self)
        self._all_radio.setFixedHeight(19)
        self._all_radio.setAutoExclusive(True)
        self._selected_radio = buttons.BaseRadioButton('Selected', parent=self)
        self._selected_radio.setFixedHeight(19)
        self._selected_radio.setChecked(True)
        self._selected_radio.setAutoExclusive(True)
        self._hierarchy_cbx = checkbox.BaseCheckBox('Hierarchy', parent=self)
        self._hierarchy_cbx.setFixedHeight(19)
        self._node_types_combo = combobox.BaseComboBox(parent=self)
        self._auto_rename_shapes_cbx = None
        self._auto_rename_shapes_cbx = checkbox.BaseCheckBox(
            'Auto Rename Shapes', parent=self)
        self._auto_rename_shapes_cbx.setChecked(True)
        if not dcc.client().is_maya():
            self._auto_rename_shapes_cbx.setVisible(False)

        selection_layout.addWidget(self._selected_radio)
        selection_layout.addWidget(self._all_radio)
        selection_layout.addItem(
            QSpacerItem(10, 0, QSizePolicy.Fixed, QSizePolicy.Fixed))
        selection_layout.addWidget(self._hierarchy_cbx)
        selection_layout.addItem(
            QSpacerItem(10, 0, QSizePolicy.Fixed, QSizePolicy.Fixed))
        selection_layout.addWidget(self._node_types_combo)
        if self._auto_rename_shapes_cbx:
            selection_layout.addItem(
                QSpacerItem(10, 0, QSizePolicy.Fixed, QSizePolicy.Fixed))
            selection_layout.addWidget(self._auto_rename_shapes_cbx)

        self._splitter = splitter.CollapsibleSplitter(parent=self)
        self._splitter.setOrientation(Qt.Horizontal)
        self._splitter.setSizePolicy(QSizePolicy.Minimum,
                                     QSizePolicy.Expanding)
        self._splitter.setMinimumHeight(750)
        self.main_layout.addWidget(self._splitter)

        self._rename_tab = tabs.BaseTabWidget(parent=self)
        self._splitter.addWidget(self._rename_tab)

        self._manual_rename_widget = manualrenamewidget.ManualRenameWidget(
            model=self._model, controller=self._controller, parent=self)
        self._auto_rename_widget = autorenamewidget.AutoRenameWidget(
            model=self._model, controller=self._controller, parent=self)

        self._rename_tab.addTab(self._manual_rename_widget, 'Manual')
        self._rename_tab.addTab(self._auto_rename_widget, 'Auto')

        self._stack = stack.SlidingStackedWidget()
        # splitter_right_widget = QWidget()
        # splitter_right_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0))
        # splitter_right_layout.addLayout(self._categories_layout)
        # splitter_right_layout.addWidget(self._stack)
        # splitter_right_widget.setLayout(splitter_right_layout)
        # self._splitter.addWidget(splitter_right_widget)
        #
        # no_items_widget = QFrame()
        # no_items_widget.setFrameShape(QFrame.StyledPanel)
        # no_items_widget.setFrameShadow(QFrame.Sunken)
        # no_items_widget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
        # no_items_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0))
        # no_items_widget.setLayout(no_items_layout)
        # no_items_lbl = label.BaseLabel()
        # no_items_pixmap = tp.ResourcesMgr().pixmap('no_items')
        # no_items_lbl.setPixmap(no_items_pixmap)
        # no_items_lbl.setAlignment(Qt.AlignCenter)
        # no_items_layout.addItem(QSpacerItem(0, 10, QSizePolicy.Preferred, QSizePolicy.Expanding))
        # no_items_layout.addWidget(no_items_lbl)
        # no_items_layout.addItem(QSpacerItem(0, 10, QSizePolicy.Preferred, QSizePolicy.Expanding))
        #
        # self._stack.addWidget(no_items_widget)

        self._splitter.handle(0).collapse()
        self._splitter.setSizes([1, 0])

    def setup_signals(self):
        self._stack.animFinished.connect(self._on_stack_anim_finished)
        self._rename_tab.currentChanged.connect(self._on_tab_changed)
        self._selected_radio.clicked.connect(self._controller.set_selected)
        self._all_radio.clicked.connect(self._controller.set_all_selection)
        self._hierarchy_cbx.toggled.connect(
            self._controller.hierarchy_check_toggle)
        self._node_types_combo.currentIndexChanged.connect(
            self._controller.set_filter_type)
        self._auto_rename_shapes_cbx.toggled.connect(
            self._controller.auto_rename_shapes_check_toggle)

        self._model.hierarchyCheckChanged.connect(
            self._on_toggle_hierarchy_cbx)
        self._model.renameShapeChanged.connect(
            self._on_toggle_auto_rename_shape_cbx)
        self._model.filterTypeChanged.connect(self._on_filter_type_changed)

    def refresh(self):
        """
        Syncs view to the current state of its model
        """

        self._hierarchy_cbx.setChecked(self._model.hierarchy_check)

        self._node_types_combo.clear()
        for btn in self._buttons_grp.buttons():
            self._buttons_grp.removeButton(btn)

        node_types = self._model.node_types
        if not node_types:
            self._node_types_combo.setVisible(False)
        else:
            self._node_types_combo.setVisible(True)
            for node_type in node_types:
                self._node_types_combo.addItem(str(node_type).split('.')[-1])

        categories = self._model.categories or dict()
        nodes_to_discard = self._model.nodes_to_discard
        types_to_discard = self._model.types_to_discard
        for node_type in types_to_discard:
            nodes_to_discard.extend(dcc.list_nodes(node_type=node_type))

        for i, category in enumerate(categories):
            for category_name, category_data in category.items():
                title = category_data.get('title', category)
                icon = category_data.get('icon', None)
                types = category_data.get('types', dict())
                category_btn = buttons.BaseButton(title)
                category_btn.setCheckable(True)
                if icon:
                    category_btn.setIcon(resources.icon(icon))
                if i == 0:
                    category_btn.setChecked(True)
                self._buttons_grp.addButton(category_btn)
                self._categories_layout.addWidget(category_btn)
                category_widget = categorywidget.CategoryWidget(
                    types=types, nodes_to_discard=nodes_to_discard)
                self._stack.addWidget(category_widget)

                # category_widget.doRefresh.connect(self._on_refresh_category)
                # category_widget.doPreview.connect(self._set_preview_names)
                # category_widget.togglePreview.connect(self.update_current_items)
                # category_widget.doRename.connect(self._on_rename)
                # category_btn.clicked.connect(partial(self._on_category_selected, i + 1))

        self._auto_rename_widget.refresh()

        self._controller.update_rules()

    def _on_stack_anim_finished(self, index):
        """
        Internal callback function that is called when stack animation is completed
        :param index:
        :return:
        """

        for btn in self._buttons_grp.buttons():
            btn.setEnabled(True)
        category_widget = self._stack.current_widget
        if not category_widget:
            return
        # self._on_refresh_category(category_widget)

    def _on_tab_changed(self, tab_index):
        """
        Internal callback function that is called when tab widget is changed by the user
        :param tab_index: int
        """

        if tab_index != 1:
            return

        self._controller.update_rules()

    def _on_toggle_hierarchy_cbx(self, flag):
        """
        Internal callback function called when the user toggles hierarchy check box
        :param flag: bool
        """

        self._hierarchy_cbx.setChecked(flag)

    def _on_toggle_auto_rename_shape_cbx(self, flag):
        """
        Internal callback function called when the user toggles auto rename shape check box
        :param flag: bool
        """

        self._auto_rename_shapes_cbx.setChecked(flag)

    def _on_filter_type_changed(self, value):
        """
        Internal callback function that is called when user changes the filter type combo box
        :param value: str
        """

        self._node_types_combo.setCurrentText(value)