Exemple #1
0
def main():
    import sys

    app = QApplication(sys.argv)

    layout = QVBoxLayout()

    infos = QSerialPortInfo.availablePorts()
    for info in infos:
        s = (
            f"Port: {info.portName()}",
            f"Location: {info.systemLocation()}",
            f"Description: {info.description()}",
            f"Manufacturer: {info.manufacturer()}",
            f"Serial number: {info.serialNumber()}",
            "Vendor Identifier: " + f"{info.vendorIdentifier():x}"
            if info.hasVendorIdentifier()
            else "",
            "Product Identifier: " + f"{info.productIdentifier():x}"
            if info.hasProductIdentifier()
            else "",
        )
        label = QLabel("\n".join(s))
        layout.addWidget(label)

    workPage = QWidget()
    workPage.setLayout(layout)

    area = QScrollArea()
    area.setWindowTitle("Info about all available serial ports.")
    area.setWidget(workPage)
    area.show()

    sys.exit(app.exec_())
Exemple #2
0
    def __init__(self, title='', animation_duration=300, parent=None):
        super(ExpandableLine, self).__init__(parent=parent)

        self._animation_duration = animation_duration

        base_layout = layouts.GridLayout(margins=(0, 0, 0, 0))
        base_layout.setVerticalSpacing(0)
        self.setLayout(base_layout)

        self.expand_btn = QToolButton()
        self.expand_btn.setText(str(title))
        self.expand_btn.setStyleSheet('QToolButton { border : none; }')
        self.expand_btn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.expand_btn.setArrowType(Qt.ArrowType.RightArrow)
        self.expand_btn.setCheckable(True)
        self.expand_btn.setChecked(True)

        header_line = QFrame()
        header_line.setFrameShape(QFrame.HLine)
        header_line.setFrameShadow(QFrame.Sunken)
        header_line.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)

        self.content_area = QScrollArea()
        self.content_area.setStyleSheet('QScrollArea { border: none;}')
        self.content_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.content_area.setMaximumHeight(0)
        self.content_area.setMinimumHeight(0)

        self.toggle_anim = QParallelAnimationGroup()
        self.toggle_anim.addAnimation(QPropertyAnimation(self, 'minimumHeight'))
        self.toggle_anim.addAnimation(QPropertyAnimation(self, 'maximumHeight'))
        self.toggle_anim.addAnimation(QPropertyAnimation(self.content_area, 'maximumHeight'))

        row = 0
        base_layout.addWidget(self.expand_btn, row, 0, 1, 1, Qt.AlignLeft)
        base_layout.addWidget(header_line, row, 2, 1, 1)
        row += 1
        base_layout.addWidget(self.content_area, row, 0, 1, 3)

        def expand_view(checked):
            arrow_type = Qt.DownArrow if checked else Qt.RightArrow
            direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward
            self.expand_btn.setArrowType(arrow_type)
            self.toggle_anim.setDirection(direction)
            self.toggle_anim.start()

        # === SIGNALS === #
        self.expand_btn.toggled.connect(expand_view)

        expand_view(True)
Exemple #3
0
    def ui(self):
        super(OptionsViewer, self).ui()

        edit_mode_icon = resources.icon('edit')
        move_up_icon = resources.icon('sort_up')
        move_down_icon = resources.icon('sort_down')
        remove_icon = resources.icon('delete')

        self._edit_widget = QWidget()
        top_layout = layouts.HorizontalLayout()
        top_layout.setContentsMargins(0, 0, 0, 0)
        top_layout.setSpacing(2)
        self._edit_widget.setLayout(top_layout)
        self.main_layout.addWidget(self._edit_widget)
        self._edit_mode_btn = buttons.BaseButton(parent=self)
        self._edit_mode_btn.setIcon(edit_mode_icon)
        self._edit_mode_btn.setCheckable(True)
        top_layout.addWidget(self._edit_mode_btn)

        horizontal_separator = QFrame()
        horizontal_separator.setFrameShape(QFrame.VLine)
        horizontal_separator.setFrameShadow(QFrame.Sunken)
        top_layout.addWidget(horizontal_separator)

        self._move_up_btn = buttons.BaseButton(parent=self)
        self.move_down_btn = buttons.BaseButton(parent=self)
        self.remove_btn = buttons.BaseButton(parent=self)
        self._move_up_btn.setIcon(move_up_icon)
        self.move_down_btn.setIcon(move_down_icon)
        self.remove_btn.setIcon(remove_icon)
        self._move_up_btn.setVisible(False)
        self.move_down_btn.setVisible(False)
        self.remove_btn.setVisible(False)
        top_layout.addWidget(self._move_up_btn)
        top_layout.addWidget(self.move_down_btn)
        top_layout.addWidget(self.remove_btn)
        top_layout.addStretch()
        self.main_layout.addWidget(dividers.Divider())

        self._scroll = QScrollArea()
        self._scroll.setSizePolicy(QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        self._scroll.setFocusPolicy(Qt.NoFocus)
        self._scroll.setWidgetResizable(True)
        self.setFocusPolicy(Qt.NoFocus)
        self._options_list = self.OPTION_LIST_CLASS(parent=self)
        self._scroll.setWidget(self._options_list)

        self.main_layout.addWidget(self._scroll)
Exemple #4
0
    def __init__(self, parent=None):
        QScrollArea.__init__(self, parent)
        self.setWidgetResizable(True)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        self._layout = QVBoxLayout()
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(Counters.SPACING)

        widget = QWidget()
        widget.setLayout(self._layout)
        self.setWidget(widget)

        self.setFixedWidth(200)
        self.checked_buttons = dict()
Exemple #5
0
    def _build_ui(self):
        self._lyt_grid.setContentsMargins(0, 0, 0, 0)
        self._lyt_grid.setSpacing(10)
        self._lyt_grid.setAlignment(Qt.AlignTop | Qt.AlignLeft)

        scroll_area = QScrollArea()
        scroll_area.setFrameStyle(0)
        scroll_area.setWidget(QWidget())
        scroll_area.widget().setLayout(self._lyt_grid)
        scroll_area.setWidgetResizable(True)

        lyt_main = QVBoxLayout()
        lyt_main.setContentsMargins(0, 0, 0, 0)
        lyt_main.setSpacing(0)
        lyt_main.addWidget(scroll_area)
        lyt_main.addWidget(self._toolbar)
        self.setLayout(lyt_main)
Exemple #6
0
    def ui(self):
        super(PreferencesWidget, self).ui()

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self._splitter = QSplitter()
        self._splitter.setOrientation(Qt.Horizontal)
        self._splitter.setSizePolicy(QSizePolicy.Preferred,
                                     QSizePolicy.Expanding)
        self._scroll_area = QScrollArea()
        self._scroll_area.setWidgetResizable(True)
        self._scroll_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        # self._scroll_area.setMinimumWidth(200)
        self._scroll_area_widget_contents = QWidget()
        # self._scroll_area_widget_contents.setGeometry(QRect(0, 0, 480, 595))
        self._scroll_area_layout = layouts.VerticalLayout(spacing=2,
                                                          margins=(1, 1, 1, 1))
        self._scroll_area_layout.setAlignment(Qt.AlignTop)
        self._scroll_area_widget_contents.setLayout(self._scroll_area_layout)
        self._categories_layout = layouts.VerticalLayout()
        self._stack = stack.SlidingStackedWidget()
        self._stack.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._stack.set_vertical_mode()
        self._buttons_layout = layouts.HorizontalLayout(spacing=1,
                                                        margins=(0, 0, 0, 0))
        self._save_prefs_close_btn = buttons.BaseButton(
            'Save and Close', icon=resources.icon('save'), parent=self)
        self._close_btn = buttons.BaseButton('Close',
                                             icon=resources.icon('cancel'),
                                             parent=self)

        self._buttons_layout.addStretch()
        self._buttons_layout.addWidget(self._save_prefs_close_btn)
        self._buttons_layout.addWidget(self._close_btn)
        self._scroll_area_layout.addLayout(self._categories_layout)
        self._scroll_area.setWidget(self._scroll_area_widget_contents)
        self._splitter.addWidget(self._scroll_area)
        self._splitter.addWidget(self._stack)
        self._splitter.setSizes([150, 450])

        self.main_layout.addWidget(self._splitter)
        self.main_layout.addWidget(dividers.Divider(parent=self))
        self.main_layout.addLayout(self._buttons_layout)
Exemple #7
0
    def ui(self):
        super(AttributeEditor, self).ui()

        self._main_group = QGroupBox()
        self._main_group.setProperty('class', 'attr_main_group')
        self._main_group.setFlat(False)
        self._main_group.setTitle('')

        self._main_group_layout = self.get_attributes_layout()
        self._main_group.setLayout(self._main_group_layout)

        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        scroll_area.setStyleSheet(
            'QScrollArea { background-color: rgb(57,57,57);}')
        scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        scroll_area.setWidget(self._main_group)

        self.main_layout.addWidget(scroll_area)

        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self._on_create_context_menu)
Exemple #8
0
    def ui(self):
        super(SliderPanel, self).ui()

        self._title_label = label.BaseLabel(parent=self).h4()
        self._title_label.setText(self._title)

        self._close_btn = buttons.BaseToolButton(
            parent=self).icon_only().image('close', theme='window').small()
        self._close_btn.setVisible(self._closable or False)

        title_layout = layouts.HorizontalLayout()
        title_layout.addWidget(self._title_label)
        title_layout.addStretch()
        title_layout.addWidget(self._close_btn)

        self._button_layout = layouts.HorizontalLayout()
        self._button_layout.addStretch()

        self._scroll_area = QScrollArea()
        self.main_layout.addLayout(title_layout)
        self.main_layout.addWidget(dividers.Divider())
        self.main_layout.addWidget(self._scroll_area)
        self.main_layout.addWidget(dividers.Divider())
        self.main_layout.addLayout(self._button_layout)
Exemple #9
0
    def _setup_colors_tab(self):
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        colors_widget = QWidget()
        colors_layout = layouts.GridLayout(spacing=2, margins=(2, 2, 2, 2))
        colors_layout.setAlignment(Qt.AlignTop)
        colors_widget.setLayout(colors_layout)
        scroll_area.setWidget(colors_widget)

        color_attribute_names = self._theme.get_color_attribute_names(
        ) or list()
        for i, color_attribute_name in enumerate(color_attribute_names):
            if not hasattr(self._theme, color_attribute_name):
                continue
            label, selector = self._add_color_widget(
                color_attribute_name, getattr(self._theme,
                                              color_attribute_name))
            colors_layout.addWidget(label, i, 0, Qt.AlignRight)
            colors_layout.addWidget(selector, i, 1)

        return scroll_area
Exemple #10
0
    def ui(self):
        super(Changelog, self).ui()
        self.set_logo('changelog_logo')

        self.main_layout.setAlignment(Qt.AlignTop)
        self.main_layout.setContentsMargins(0, 0, 0, 0)

        self.setFixedWidth(600)
        self.setMaximumHeight(800)

        scroll_layout = layouts.VerticalLayout(spacing=2, margins=(2, 2, 2, 2))
        scroll_layout.setAlignment(Qt.AlignTop)
        central_widget = QWidget()
        central_widget.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        scroll = QScrollArea()
        scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scroll.setWidgetResizable(True)
        scroll.setFocusPolicy(Qt.NoFocus)
        ok_btn = QPushButton('OK')
        ok_btn.clicked.connect(self.close)
        self.main_layout.addWidget(scroll)
        self.main_layout.setAlignment(Qt.AlignTop)
        self.main_layout.addWidget(ok_btn)
        scroll.setWidget(central_widget)
        central_widget.setLayout(scroll_layout)
        self.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        self.main_layout = scroll_layout

        # ===========================================================================================

        self.version_accordion = accordion.AccordionWidget(parent=self)
        self.version_accordion.rollout_style = accordion.AccordionStyle.MAYA
        self.main_layout.addWidget(self.version_accordion)

        # ===========================================================================================

        changelog_json_file = os.path.join(
            os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
            'changelog.json')
        if not os.path.isfile(changelog_json_file):
            return

        with open(changelog_json_file, 'r') as f:
            changelog_data = json.load(f, object_pairs_hook=OrderedDict)
        if not changelog_data:
            return

        changelog_data = OrderedDict(
            sorted(changelog_data.items(), reverse=True))

        for version, elements in changelog_data.items():
            self._create_version(version, elements)

        last_version_item = self.version_accordion.item_at(0)
        last_version_item.set_collapsed(False)
Exemple #11
0
    def ui(self):
        """
        Function that sets up the ui of the widget
        Override it on new widgets (but always call super)
        """

        self.main_layout = self.get_main_layout()
        if self._use_scrollbar:
            layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0))
            self.setLayout(layout)
            central_widget = QWidget()
            central_widget.setSizePolicy(
                QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
            scroll = QScrollArea()
            scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
            scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            scroll.setWidgetResizable(True)
            scroll.setFocusPolicy(Qt.NoFocus)
            layout.addWidget(scroll)
            scroll.setWidget(central_widget)
            central_widget.setLayout(self.main_layout)
            self.setSizePolicy(
                QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        else:
            self.setLayout(self.main_layout)
    def ui(self):
        super(InterpolateItView, self).ui()

        central_layout = layouts.VerticalLayout(spacing=0,
                                                margins=(0, 0, 0, 0))
        central_widget = QWidget()
        central_widget.setLayout(central_layout)
        central_widget.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        scroll = QScrollArea()
        scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scroll.setWidgetResizable(True)
        scroll.setFocusPolicy(Qt.NoFocus)
        self.main_layout.addWidget(scroll)
        scroll.setWidget(central_widget)

        self._interpolator_layout = layouts.VerticalLayout(spacing=0,
                                                           margins=(0, 0, 0,
                                                                    0))
        self._interpolator_layout.setAlignment(Qt.AlignTop)

        button_layout = layouts.HorizontalLayout(spacing=2,
                                                 margins=(0, 0, 0, 0))
        self._load_btn = buttons.BaseButton('Load', parent=self)
        self._save_btn = buttons.BaseButton('Save', parent=self)
        self._add_btn = buttons.BaseButton('New', parent=self)
        button_layout.addWidget(self._save_btn)
        button_layout.addWidget(self._load_btn)
        button_layout.addStretch()
        button_layout.addWidget(self._add_btn)

        central_layout.addLayout(self._interpolator_layout)

        self.main_layout.addLayout(button_layout)
Exemple #13
0
class OptionsViewer(base.BaseWidget):

    OPTION_LIST_CLASS = optionlist.OptionList

    editModeChanged = Signal(bool)

    def __init__(self, option_object=None, settings=None, parent=None):

        self._option_object = None
        self._settings = settings
        self._edit_mode = False
        self._current_widgets = list()
        self._widget_to_copy = None

        super(OptionsViewer, self).__init__(parent)

        policy = self.sizePolicy()
        policy.setHorizontalPolicy(policy.Expanding)
        policy.setVerticalPolicy(policy.Expanding)
        self.main_layout.setContentsMargins(2, 2, 2, 2)
        self.main_layout.setSpacing(2)
        self.setSizePolicy(policy)

        if option_object:
            self.set_option_object(option_object=option_object)

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

        edit_mode_icon = resources.icon('edit')
        move_up_icon = resources.icon('sort_up')
        move_down_icon = resources.icon('sort_down')
        remove_icon = resources.icon('delete')

        self._edit_widget = QWidget()
        top_layout = layouts.HorizontalLayout()
        top_layout.setContentsMargins(0, 0, 0, 0)
        top_layout.setSpacing(2)
        self._edit_widget.setLayout(top_layout)
        self.main_layout.addWidget(self._edit_widget)
        self._edit_mode_btn = buttons.BaseButton(parent=self)
        self._edit_mode_btn.setIcon(edit_mode_icon)
        self._edit_mode_btn.setCheckable(True)
        top_layout.addWidget(self._edit_mode_btn)

        horizontal_separator = QFrame()
        horizontal_separator.setFrameShape(QFrame.VLine)
        horizontal_separator.setFrameShadow(QFrame.Sunken)
        top_layout.addWidget(horizontal_separator)

        self._move_up_btn = buttons.BaseButton(parent=self)
        self.move_down_btn = buttons.BaseButton(parent=self)
        self.remove_btn = buttons.BaseButton(parent=self)
        self._move_up_btn.setIcon(move_up_icon)
        self.move_down_btn.setIcon(move_down_icon)
        self.remove_btn.setIcon(remove_icon)
        self._move_up_btn.setVisible(False)
        self.move_down_btn.setVisible(False)
        self.remove_btn.setVisible(False)
        top_layout.addWidget(self._move_up_btn)
        top_layout.addWidget(self.move_down_btn)
        top_layout.addWidget(self.remove_btn)
        top_layout.addStretch()
        self.main_layout.addWidget(dividers.Divider())

        self._scroll = QScrollArea()
        self._scroll.setSizePolicy(QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        self._scroll.setFocusPolicy(Qt.NoFocus)
        self._scroll.setWidgetResizable(True)
        self.setFocusPolicy(Qt.NoFocus)
        self._options_list = self.OPTION_LIST_CLASS(parent=self)
        self._scroll.setWidget(self._options_list)

        self.main_layout.addWidget(self._scroll)

    def setup_signals(self):
        self._edit_mode_btn.toggled.connect(self._on_edit_mode)
        self._move_up_btn.clicked.connect(self._on_move_up)
        self.move_down_btn.clicked.connect(self._on_move_down)
        self.remove_btn.clicked.connect(self._on_remove)

    def settings(self):
        """
        Returns settings object
        :return: JSONSettings
        """

        return self._settings

    def set_settings(self, settings):
        """
        Sets save widget settings
        :param settings: JSONSettings
        """

        self._settings = settings

    def get_option_object(self):
        """
        Returns the option object linked to this widget
        :return: object
        """

        return self._option_object

    def set_option_object(self, option_object, force_update=True):
        """
        Sets option_object linked to this widget
        :param option_object: object
        :param force_update: bool
        """

        self._option_object = option_object
        self._options_list.set_option_object(option_object)
        if option_object and force_update:
            self.update_options()

    def get_option_type(self):
        """
        Returns option widget type
        :return: str
        """

        return self._option_type

    def is_edit_mode(self):
        """
        Returns whether current option is editable or not
        :return: bool
        """

        return self._edit_mode

    def set_edit_mode(self, flag):
        """
        Sets whether the current option is editable or not
        :param flag: bool
        """

        self._on_edit_mode(flag)

    def is_widget_to_copy(self):
        """
        Returns whether an option widget is being copied or not
        :return: bool
        """

        return self._widget_to_copy

    def set_widget_to_copy(self, widget_to_copy):
        """
        Sets widget that we want to copy
        :param QWidget
        """

        self._widget_to_copy = widget_to_copy

    def show_edit_widget(self):
        self._edit_widget.setVisible(True)
        self._edit_splitter.setVisible(True)

    def hide_edit_widget(self):
        self._edit_widget.setVisible(False)
        self._edit_splitter.setVisible(False)

    def update_options(self):
        """
        Function that updates the current options of the selected task
        """

        if not self._option_object:
            self._options_list.clear_widgets()
            LOGGER.warning(
                'Impossible to update options because option object is not defined!'
            )
            return

        self._options_list.update_options()

    def clear_options(self):
        """
        Clears all the options
        """

        self._options_list.clear_widgets()
        if self._option_object:
            self._option_object = None

    def has_options(self):
        """
        Checks if the current task has options or not
        :return: bool
        """

        if not self._option_object:
            LOGGER.warning(
                'Impossible to check options because option object is not defined!'
            )
            return

        return self._option_object.has_options()

    def _edit_activate(self, edit_value):
        """
        Internal function that updates widget states when edit button is pressed
        :param edit_value: bool
        """

        self._edit_mode = edit_value
        self.move_down_btn.setVisible(edit_value)
        self._move_up_btn.setVisible(edit_value)
        self.remove_btn.setVisible(edit_value)
        if not edit_value:
            self._options_list.clear_selection()
        self._options_list.set_edit(edit_value)

    def _on_edit_mode(self, edit_value):
        """
        Internal callback function that is called when the user presses edit mode button
        :param edit_value: bool
        """

        self._edit_activate(edit_value)
        self.editModeChanged.emit(edit_value)

    def _on_move_up(self):
        """
        Internal callback function that is called when the user pressed move up button
        Move selected items up in the list
        """

        widgets = self._current_widgets
        if not widgets:
            return

        widgets = self._options_list.sort_widgets(widgets,
                                                  widgets[0].get_parent())
        if not widgets:
            return
        for w in widgets:
            w.move_up()

    def _on_move_down(self):
        """
        Internal callback function that is called when the user pressed move down button
        Move selected items down in the list
        """

        widgets = self._current_widgets
        if not widgets:
            return

        widgets = self._options_list.sort_widgets(widgets,
                                                  widgets[0].get_parent())
        if not widgets:
            return
        for w in widgets:
            w.move_down()

    def _on_remove(self):
        """
        Internal callback function that is called when the user pressed remove button
        Remove selected options
        """

        widgets = self._current_widgets
        if not widgets:
            return

        widgets = self._options_list.sort_widgets(widgets,
                                                  widgets[0].get_parent())
        if not widgets:
            return
        for w in widgets:
            w.remove()
Exemple #14
0
class PreferencesWidget(base.BaseWidget, object):

    closed = Signal(bool, dict)

    def __init__(self, settings=None, parent=None):
        self._settings = settings
        super(PreferencesWidget, self).__init__(parent=parent)

        self._indexes = dict()
        self._category_buttons = dict()
        self._settings = settings

        self._try_create_defaults()

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

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self._splitter = QSplitter()
        self._splitter.setOrientation(Qt.Horizontal)
        self._splitter.setSizePolicy(QSizePolicy.Preferred,
                                     QSizePolicy.Expanding)
        self._scroll_area = QScrollArea()
        self._scroll_area.setWidgetResizable(True)
        self._scroll_area.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        # self._scroll_area.setMinimumWidth(200)
        self._scroll_area_widget_contents = QWidget()
        # self._scroll_area_widget_contents.setGeometry(QRect(0, 0, 480, 595))
        self._scroll_area_layout = layouts.VerticalLayout(spacing=2,
                                                          margins=(1, 1, 1, 1))
        self._scroll_area_layout.setAlignment(Qt.AlignTop)
        self._scroll_area_widget_contents.setLayout(self._scroll_area_layout)
        self._categories_layout = layouts.VerticalLayout()
        self._stack = stack.SlidingStackedWidget()
        self._stack.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._stack.set_vertical_mode()
        self._buttons_layout = layouts.HorizontalLayout(spacing=1,
                                                        margins=(0, 0, 0, 0))
        self._save_prefs_close_btn = buttons.BaseButton(
            'Save and Close', icon=resources.icon('save'), parent=self)
        self._close_btn = buttons.BaseButton('Close',
                                             icon=resources.icon('cancel'),
                                             parent=self)

        self._buttons_layout.addStretch()
        self._buttons_layout.addWidget(self._save_prefs_close_btn)
        self._buttons_layout.addWidget(self._close_btn)
        self._scroll_area_layout.addLayout(self._categories_layout)
        self._scroll_area.setWidget(self._scroll_area_widget_contents)
        self._splitter.addWidget(self._scroll_area)
        self._splitter.addWidget(self._stack)
        self._splitter.setSizes([150, 450])

        self.main_layout.addWidget(self._splitter)
        self.main_layout.addWidget(dividers.Divider(parent=self))
        self.main_layout.addLayout(self._buttons_layout)

    def setup_signals(self):
        self._save_prefs_close_btn.clicked.connect(
            self._on_save_and_close_prefs)
        self._close_btn.clicked.connect(self._on_close)

    def showEvent(self, event):
        settings = self.settings()
        if not settings:
            return

        groups = settings.childGroups()
        for name, index_widget in self._indexes.items():
            index, widget = index_widget
            settings.beginGroup(name)
            if name not in groups:
                widget.init_defaults(settings)
            widget.show_widget(settings)
            settings.endGroup()

    def settings(self):
        return self._settings

    def set_settings(self, settings):
        if not settings:
            return
        self._settings = settings
        self._try_create_defaults()

    def add_category(self, name, widget):
        category_button = CategoryButton(text=name, parent=self)
        self._categories_layout.insertWidget(
            self._categories_layout.count() - 2, category_button)
        widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        index = self._stack.addWidget(widget)
        self._indexes[name] = (index, widget)
        self._category_buttons[index] = category_button
        category_button.clicked.connect(lambda checked=False, idx=index: self.
                                        _on_switch_category_content(idx))
        widget.init_defaults(settings=self.settings())
        self.closed.connect(widget._on_reset)

    def select_by_name(self, name):
        if name not in self._indexes:
            return
        index = self._indexes[name][0]
        self._stack.setCurrentIndex(index)
        self._category_buttons[index].setChecked(True)

    def _try_create_defaults(self):
        settings = self.settings()
        if not settings:
            return

        groups = settings.childGroups()
        for name, index_widget in self._indexes.items():
            index, widget = index_widget
            init_defaults = False
            if name not in groups:
                init_defaults = True
            settings.beginGroup(name)
            if init_defaults:
                widget.init_defaults(settings)
            settings.endGroup()
        settings.sync()

    def _on_switch_category_content(self, index):
        self._stack.slide_in_index(index)
        self._category_buttons[index].toggle()

    def _on_save_prefs(self):
        settings = self.settings()
        if not settings:
            return

        stored_data = dict()

        for name, index_widget in self._indexes.items():
            index, widget = index_widget
            settings.beginGroup(name)
            data = widget.serialize(settings)
            if data:
                stored_data[name] = data
            settings.endGroup()
        settings.sync()

        return stored_data

    def _on_save_and_close_prefs(self):
        stored_data = self._on_save_prefs()
        self.closed.emit(True, stored_data)

    def _on_close(self):
        self.closed.emit(False, None)
Exemple #15
0
class SliderPanel(base.BaseWidget, object):
    """
    Panel that slides in from the edge of the window
    """

    closed = Signal()
    closeButtonClicked = Signal()

    def __init__(self,
                 title,
                 position=SliderPanelPositions.RIGHT,
                 closable=True,
                 parent=None):

        self._title = title
        self._position = position
        self._closable = closable
        self._is_first_close = True

        super(SliderPanel, self).__init__(parent)

        self.setObjectName('sliderPanel')
        self.setWindowFlags(Qt.Popup)
        self.setAttribute(Qt.WA_StyledBackground)

        self._close_timer = QTimer(self)
        self._close_timer.setInterval(300)
        self._close_timer.setSingleShot(True)
        self._close_timer.timeout.connect(self.close)
        self._close_timer.timeout.connect(self.closed.emit)

        self._pos_anim = QPropertyAnimation(self)
        self._pos_anim.setTargetObject(self)
        self._pos_anim.setEasingCurve(QEasingCurve.OutCubic)
        self._pos_anim.setDuration(300)
        self._pos_anim.setPropertyName(b'pos')

        self._opacity_anim = QPropertyAnimation()
        self._opacity_anim.setTargetObject(self)
        self._opacity_anim.setDuration(300)
        self._opacity_anim.setEasingCurve(QEasingCurve.OutCubic)
        self._opacity_anim.setPropertyName(b'windowOpacity')
        self._opacity_anim.setStartValue(0.0)
        self._opacity_anim.setEndValue(1.0)

    # =================================================================================================================
    # PROPERTIES
    # =================================================================================================================

    @property
    def position(self):
        """
        Returns the placement of the panel in parent window
        :return: str
        """

        return self._position

    @position.setter
    def position(self, value):
        """
        Sets the position of the panel in parent window ('top', 'right', 'bottom' or 'left').
        :param value: str
        """

        self._position = value
        if value in [SliderPanelPositions.BOTTOM, SliderPanelPositions.TOP]:
            self.setFixedHeight(200)
        else:
            self.setFixedWidth(200)

    # =================================================================================================================
    # OVERRIDES
    # =================================================================================================================

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

        self._title_label = label.BaseLabel(parent=self).h4()
        self._title_label.setText(self._title)

        self._close_btn = buttons.BaseToolButton(
            parent=self).icon_only().image('close', theme='window').small()
        self._close_btn.setVisible(self._closable or False)

        title_layout = layouts.HorizontalLayout()
        title_layout.addWidget(self._title_label)
        title_layout.addStretch()
        title_layout.addWidget(self._close_btn)

        self._button_layout = layouts.HorizontalLayout()
        self._button_layout.addStretch()

        self._scroll_area = QScrollArea()
        self.main_layout.addLayout(title_layout)
        self.main_layout.addWidget(dividers.Divider())
        self.main_layout.addWidget(self._scroll_area)
        self.main_layout.addWidget(dividers.Divider())
        self.main_layout.addLayout(self._button_layout)

    def setup_signals(self):
        self._close_btn.clicked.connect(self.close)
        self._close_btn.clicked.connect(self.closeButtonClicked.emit)

    def show(self):
        self._update_position()
        self._fade_in()

        return super(SliderPanel, self).show()

    def closeEvent(self, event):
        if self._is_first_close:
            self._is_first_close = False
            self._close_timer.stop()
            self._fade_out()
            self.closed.emit()
            event.ignore()
        else:
            event.accept()

    # =================================================================================================================
    # BASE
    # =================================================================================================================

    def set_widget(self, widget):
        """
        Sets the widget that will be contained inside the panel
        :param widget: QWidget
        """

        self._scroll_area.setWidget(widget)

    def add_button(self, button):
        """
        Adds a new button to the bottom part of the panel
        :param button: QPushButton
        """

        self._button_layout.addWidget(button)

    def left(self):
        """
        Sets the panel's placement to left
        :return: SliderPanel
        """

        self.position = SliderPanelPositions.LEFT

        return self

    def right(self):
        """
        Sets the panel's placement to right
        :return: SliderPanel
        """

        self.position = SliderPanelPositions.RIGHT

        return self

    def top(self):
        """
        Sets the panel's placement to top
        :return: SliderPanel
        """

        self.position = SliderPanelPositions.TOP

        return self

    def bottom(self):
        """
        Sets the panel's placement to bottom
        :return: SliderPanel
        """

        self.position = SliderPanelPositions.BOTTOM

        return self

    # =================================================================================================================
    # INTERNAL
    # =================================================================================================================

    def _fade_in(self):
        """
        Internal function that fades in the panel
        """

        self._pos_anim.start()
        self._opacity_anim.start()

    def _fade_out(self):
        """
        Internal function that fades out the panel
        """

        self._pos_anim.setDirection(QAbstractAnimation.Backward)
        self._pos_anim.start()
        self._opacity_anim.setDirection(QAbstractAnimation.Backward)
        self._opacity_anim.start()

    def _update_position(self):
        """
        Internal function that makes sure that panel is positioned in the proper place
        """

        parent = self.parent()
        parent_parent = parent.parent()
        dcc_win = dcc.get_main_window()
        dcc_window = parent_parent == dcc_win
        if parent_parent and dcc_win:
            dcc_window = dcc_window or parent_parent.objectName(
            ) == dcc_win.objectName()
        parent_geo = parent.geometry()
        if self._position == SliderPanelPositions.LEFT:
            pos = parent_geo.topLeft() if dcc_window else parent.mapToGlobal(
                parent_geo.topLeft())
            target_x = pos.x()
            target_y = pos.y()
            self.setFixedHeight(parent_geo.height())
            self._pos_anim.setStartValue(
                QPoint(target_x - self.width(), target_y))
            self._pos_anim.setEndValue(QPoint(target_x, target_y))
        if self._position == SliderPanelPositions.RIGHT:
            pos = parent_geo.topRight() if dcc_window else parent.mapToGlobal(
                parent_geo.topRight())
            self.setFixedHeight(parent_geo.height())
            target_x = pos.x() - self.width()
            target_y = pos.y()
            self._pos_anim.setStartValue(
                QPoint(target_x + self.width(), target_y))
            self._pos_anim.setEndValue(QPoint(target_x, target_y))
        if self._position == SliderPanelPositions.TOP:
            pos = parent_geo.topLeft(
            ) if dcc_window or parent_parent is None else parent.mapToGlobal(
                parent_geo.topLeft())
            self.setFixedWidth(parent_geo.width())
            target_x = pos.x()
            target_y = pos.y()
            self._pos_anim.setStartValue(
                QPoint(target_x, target_y - self.height()))
            self._pos_anim.setEndValue(QPoint(target_x, target_y))
        if self._position == SliderPanelPositions.BOTTOM:
            pos = parent_geo.bottomLeft(
            ) if dcc_window else parent.mapToGlobal(parent_geo.bottomLeft())
            self.setFixedWidth(parent_geo.width())
            target_x = pos.x()
            target_y = pos.y() - self.height()
            self._pos_anim.setStartValue(
                QPoint(target_x, target_y + self.height()))
            self._pos_anim.setEndValue(QPoint(target_x, target_y))