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_())
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)
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)
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)
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
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)
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()
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)
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))