From 755625d0290b0ad6767884d679afb65be8bd3ad4 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Fri, 5 Mar 2021 22:10:01 -0500 Subject: [PATCH] Statusbar: Add custom widgets to the default layout instead of replacing it That will allow developers to have an icon, label and spinner for their widgets, in case they need them. --- spyder/api/widgets/status.py | 161 ++++++++++-------- .../statusbar/widgets/tests/test_status.py | 4 + 2 files changed, 90 insertions(+), 75 deletions(-) diff --git a/spyder/api/widgets/status.py b/spyder/api/widgets/status.py index 2a908a11f10..eeb8f1e157a 100644 --- a/spyder/api/widgets/status.py +++ b/spyder/api/widgets/status.py @@ -23,9 +23,12 @@ class StatusBarWidget(QWidget, SpyderWidgetMixin): """ Base class for status bar widgets. - These widgets consist of an icon, a label and (optionally) a - spinner. However, you can use any QWidget in the status bar by - passing its class to CUSTOM_WIDGET_CLASS. + These widgets consist by default of an icon, a label and a spinner, + which are organized from left to right on that order. + + You can also add any other QWidget to this layout by setting the + CUSTOM_WIDGET_CLASS class attribute. It'll be put between the label + and the spinner. """ ID = None @@ -35,9 +38,7 @@ class StatusBarWidget(QWidget, SpyderWidgetMixin): CUSTOM_WIDGET_CLASS = None """ - Custom widget class to use instead of the default widget layout. - This will completely override the widget API, which won't have - any effect. + Custom widget class to add to the default layout. """ sig_option_changed = Signal(str, object) @@ -51,47 +52,93 @@ class StatusBarWidget(QWidget, SpyderWidgetMixin): This signal is emmitted when the widget is clicked. """ - def __init__(self, parent=None, show_spinner=False): - """Status bar widget base.""" + def __init__(self, parent=None, show_icon=True, show_label=True, + show_spinner=False): + """ + Base class for status bar widgets. + + These are composed of the following widgets, which are arranged + in a QHBoxLayout from left to right: + + * Icon + * Label + * Custom QWidget + * Spinner + + Parameters + ---------- + show_icon: bool + Show an icon in the widget. + show_label: bool + Show a label in the widget. + show_spinner: bool + Show a spinner. + + Notes + ----- + 1. To use an icon, you need to redefine the ``get_icon`` method. + 2. To use a label, you need to call ``set_value``. + """ super().__init__(parent) self._parent = parent + + self.show_icon = show_icon + self.show_label = show_label self.show_spinner = show_spinner + + self.value = None + self.label_icon = None + self.label_value = None self.spinner = None + self.custom_widget = None + + self.set_layout() + def set_layout(self): + """Set layout for default widgets.""" + # Icon + if self.show_icon: + self._icon = self.get_icon() + self._pixmap = None + self._icon_size = QSize(16, 16) # Should this be adjustable? + self.label_icon = QLabel() + self.set_icon() + + # Label + if self.show_label: + self.label_value = QLabel() + self.set_value('') + + # See spyder-ide/spyder#9044. + self.text_font = QFont(QFont().defaultFamily(), + weight=QFont.Normal) + self.label_value.setAlignment(Qt.AlignRight | Qt.AlignVCenter) + self.label_value.setFont(self.text_font) + + # Custom widget if self.CUSTOM_WIDGET_CLASS: if not issubclass(self.CUSTOM_WIDGET_CLASS, QWidget): raise SpyderAPIError( 'Any custom status widget must subclass QWidget!' ) - self.custom_widget = self.CUSTOM_WIDGET_CLASS(parent) - self.set_custom_layout() - else: - self.custom_widget = None - self.set_default_layout() - - def set_default_layout(self): - """Set layout for default widgets.""" - # Variables - self.value = None + self.custom_widget = self.CUSTOM_WIDGET_CLASS(self._parent) - # Widget - self._icon = self.get_icon() - self._pixmap = None - self._icon_size = QSize(16, 16) # Should this be adjustable? - self.label_icon = QLabel() - self.label_value = QLabel() + # Spinner if self.show_spinner: self.spinner = create_waitspinner(size=14, parent=self) + self.spinner.hide() # Layout setup layout = QHBoxLayout(self) layout.setSpacing(0) # Reduce space between icon and label - layout.addWidget(self.label_icon) - layout.addWidget(self.label_value) - + if self.show_icon: + layout.addWidget(self.label_icon) + if self.show_label: + layout.addWidget(self.label_value) + if self.custom_widget: + layout.addWidget(self.custom_widget) if self.show_spinner: layout.addWidget(self.spinner) - self.spinner.hide() if is_dark_interface(): layout.addSpacing(0) @@ -101,67 +148,31 @@ def set_default_layout(self): layout.setContentsMargins(0, 0, 0, 0) layout.setAlignment(Qt.AlignVCenter) - # Widget setup - self.set_icon() - - # See spyder-ide/spyder#9044. - self.text_font = QFont(QFont().defaultFamily(), weight=QFont.Normal) - self.label_value.setAlignment(Qt.AlignRight) - self.label_value.setFont(self.text_font) - # Setup - self.set_value('') self.update_tooltip() - def set_custom_layout(self): - """Set layout for custom widgets.""" - if self.show_spinner: - self.spinner = create_waitspinner(size=14, parent=self) - - layout = QHBoxLayout(self) - layout.setSpacing(0) - layout.addWidget(self.custom_widget) - - if self.show_spinner: - layout.addWidget(self.spinner) - self.spinner.hide() - - if is_dark_interface(): - layout.addSpacing(0) - else: - layout.addSpacing(10) - - layout.setContentsMargins(0, 0, 0, 0) - layout.setAlignment(Qt.AlignVCenter) - # ---- Status bar widget API def set_icon(self): """Set the icon for the status bar widget.""" - if self.custom_widget: - return - - icon = self._icon - self.label_icon.setVisible(icon is not None) - if icon is not None and isinstance(icon, QIcon): - self._pixmap = icon.pixmap(self._icon_size) - self.label_icon.setPixmap(self._pixmap) + if self.label_icon: + icon = self._icon + self.label_icon.setVisible(icon is not None) + if icon is not None and isinstance(icon, QIcon): + self._pixmap = icon.pixmap(self._icon_size) + self.label_icon.setPixmap(self._pixmap) def set_value(self, value): """Set formatted text value.""" - if self.custom_widget: - return - - self.value = value - self.label_value.setText(value) + if self.label_value: + self.value = value + self.label_value.setText(value) def update_tooltip(self): """Update tooltip for widget.""" - if self.custom_widget: - return - tooltip = self.get_tooltip() if tooltip: - self.label_value.setToolTip(tooltip) + if self.label_value: + self.label_value.setToolTip(tooltip) if self.label_icon: self.label_icon.setToolTip(tooltip) self.setToolTip(tooltip) diff --git a/spyder/plugins/statusbar/widgets/tests/test_status.py b/spyder/plugins/statusbar/widgets/tests/test_status.py index 01608414a1a..db3da55d88e 100644 --- a/spyder/plugins/statusbar/widgets/tests/test_status.py +++ b/spyder/plugins/statusbar/widgets/tests/test_status.py @@ -69,6 +69,9 @@ class CustomStatusBarWidget(StatusBarWidget): ID = 'custom_status' CUSTOM_WIDGET_CLASS = MyComboBox + def get_icon(self): + return self.create_icon('environment') + def test_status_bar_widget_signal(status_bar, qtbot): plugin, window = status_bar @@ -92,6 +95,7 @@ def test_custom_widget(status_bar, qtbot): # Add widget to status bar w = CustomStatusBarWidget(window) + w.set_value('Options: ') plugin.add_status_widget(w) # qtbot.stop()