Skip to content

Commit

Permalink
Merge pull request #22006 from ccordoba12/fix-adding-to-corner-widget
Browse files Browse the repository at this point in the history
PR: Fix adding corner widgets in dockable plugins (API)
  • Loading branch information
ccordoba12 authored Apr 18, 2024
2 parents 845b331 + 8ad804e commit 0f6b0b3
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 61 deletions.
14 changes: 14 additions & 0 deletions spyder/api/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,17 @@
"""
Widgets to extend Spyder through its API.
"""


class PluginMainWidgetWidgets:
CornerWidget = 'corner_widget'
MainToolbar = 'main_toolbar_widget'
OptionsToolButton = 'options_button_widget'
Spinner = 'spinner_widget'


class PluginMainWidgetActions:
ClosePane = 'close_pane'
DockPane = 'dock_pane'
UndockPane = 'undock_pane'
LockUnlockPosition = 'lock_unlock_position'
62 changes: 55 additions & 7 deletions spyder/api/widgets/auxiliary_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

# Local imports
from spyder.api.exceptions import SpyderAPIError
from spyder.api.widgets import PluginMainWidgetWidgets
from spyder.api.widgets.mixins import SpyderMainWindowMixin
from spyder.utils.stylesheet import APP_STYLESHEET

Expand Down Expand Up @@ -84,21 +85,68 @@ def __init__(self, parent, name):
self._strut.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.addWidget(self._strut)

def add_widget(self, widget_id, widget):
def add_widget(self, widget, before=None):
"""
Add a widget to the left of the last widget added to the corner.
"""
if widget_id in self._widgets:
if not hasattr(widget, "name") or (
before is not None and not hasattr(before, "name")
):
raise SpyderAPIError(
f"Widget {widget} or {before} doesn't have a name, which must "
f"be provided by the attribute `name`"
)

if widget.name in self._widgets:
raise SpyderAPIError(
'Wigdet with name "{}" already added. Current names are: {}'
''.format(widget_id, list(self._widgets.keys()))
''.format(widget.name, list(self._widgets.keys()))
)

if before is not None and before.name not in self._widgets:
raise SpyderAPIError(
f"Wigdet with name '{before.name}' not in this corner widget"
)

if (
not self._widgets
and widget.name != PluginMainWidgetWidgets.OptionsToolButton
):
raise SpyderAPIError(
"The options button must be the first one to be added to the "
"corner widget of dockable plugins."
)

widget.ID = widget_id
self._widgets[widget_id] = widget
self._actions.append(self.addWidget(widget))
if widget.name == PluginMainWidgetWidgets.OptionsToolButton:
# This is only necessary for the options button because it's the
# first one to be added
action = self.addWidget(widget)
else:
if before is not None:
before_action = self.get_action(before.name)
else:
# By default other buttons are added to the left of the last
# one
before_action = self._actions[-1]

# Allow to add either widgets or actions
if isinstance(widget, QWidget):
action = self.insertWidget(before_action, widget)
else:
action = widget
self.insertAction(before_action, action)
widget = self.widgetForAction(action)
widget.name = action.name

self._widgets[widget.name] = (widget, action)
self._actions.append(action)

def get_widget(self, widget_id):
"""Return a widget by unique id."""
if widget_id in self._widgets:
return self._widgets[widget_id]
return self._widgets[widget_id][0]

def get_action(self, widget_id):
"""Return action corresponding to `widget_id`."""
if widget_id in self._widgets:
return self._widgets[widget_id][1]
4 changes: 2 additions & 2 deletions spyder/api/widgets/main_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
from qtpy.QtCore import Signal
from qtpy.QtWidgets import QWidget

from spyder.api.widgets.mixins import SpyderToolbarMixin, SpyderWidgetMixin
from spyder.api.widgets.mixins import SpyderWidgetMixin


class PluginMainContainer(QWidget, SpyderWidgetMixin, SpyderToolbarMixin):
class PluginMainContainer(QWidget, SpyderWidgetMixin):
"""
Spyder plugin main container class.
Expand Down
53 changes: 17 additions & 36 deletions spyder/api/widgets/main_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@

# Local imports
from spyder.api.translations import _
from spyder.api.widgets import PluginMainWidgetActions, PluginMainWidgetWidgets
from spyder.api.widgets.auxiliary_widgets import (MainCornerWidget,
SpyderWindowWidget)
from spyder.api.widgets.menus import (
PluginMainWidgetOptionsMenu,
OptionsMenuSections,
PluginMainWidgetMenus
)
from spyder.api.widgets.mixins import SpyderToolbarMixin, SpyderWidgetMixin
from spyder.api.widgets.mixins import SpyderWidgetMixin
from spyder.api.widgets.toolbars import MainWidgetToolbar
from spyder.py3compat import qbytearray_to_str
from spyder.utils.qthelpers import create_waitspinner
Expand All @@ -48,21 +49,7 @@
logger = logging.getLogger(__name__)


class PluginMainWidgetWidgets:
CornerWidget = 'corner_widget'
MainToolbar = 'main_toolbar_widget'
OptionsToolButton = 'options_button_widget'
Spinner = 'spinner_widget'


class PluginMainWidgetActions:
ClosePane = 'close_pane'
DockPane = 'dock_pane'
UndockPane = 'undock_pane'
LockUnlockPosition = 'lock_unlock_position'


class PluginMainWidget(QWidget, SpyderWidgetMixin, SpyderToolbarMixin):
class PluginMainWidget(QWidget, SpyderWidgetMixin):
"""
Spyder plugin main widget class.
Expand Down Expand Up @@ -257,7 +244,9 @@ def __init__(self, name, plugin, parent=None):
self._spinner = None

if self.ENABLE_SPINNER:
self._spinner = create_waitspinner(size=16, parent=self)
self._spinner = create_waitspinner(
size=16, parent=self, name=PluginMainWidgetWidgets.Spinner
)

self._corner_widget = MainCornerWidget(
parent=self,
Expand Down Expand Up @@ -348,16 +337,10 @@ def _setup(self):
icon=self.create_icon('tooloptions'),
)

if self.ENABLE_SPINNER:
self.add_corner_widget(
PluginMainWidgetWidgets.Spinner,
self._spinner,
)
self.add_corner_widget(self._options_button)

self.add_corner_widget(
PluginMainWidgetWidgets.OptionsToolButton,
self._options_button,
)
if self.ENABLE_SPINNER:
self.add_corner_widget(self._spinner)

# Widget setup
# --------------------------------------------------------------------
Expand Down Expand Up @@ -518,28 +501,26 @@ def get_action(self, name, context: Optional[str] = None,

return ACTION_REGISTRY.get_reference(name, plugin, context)

def add_corner_widget(self, widget_id, widget, before=None):
def add_corner_widget(self, action_or_widget, before=None):
"""
Add widget to corner, that is to the left of the last added widget.
Parameters
----------
widget_id: str
Unique name of the widget.
widget: QWidget
Any QWidget to add in the corner widget.
before: QWidget
Insert the widget before this widget.
action_or_widget: QAction or QWidget
Any action or widget to add to the corner widget.
before: QAction or QWidget
Insert action_or_widget before this one.
Notes
-----
By default widgets are added to the left of the last corner widget.
The central widget provides an options menu button and a spinner so any
additional widgets will be placed to the left of the spinner,
if visible.
additional widgets will be placed by default to the left of the
spinner, if visible.
"""
self._corner_widget.add_widget(widget_id, widget)
self._corner_widget.add_widget(action_or_widget, before=before)

def get_corner_widget(self, name):
"""
Expand Down
6 changes: 6 additions & 0 deletions spyder/plugins/ipythonconsole/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,9 @@ class ClientContextMenuActions:
# Svg section
CopySvg = 'copy_svg'
SaveSvg = 'save_svg'


class IPythonConsoleWidgetCornerWidgets:
ResetButton = "reset_button"
InterruptButton = "interrupt_button"
TimeElapsedLabel = "time_elapsed_label"
16 changes: 10 additions & 6 deletions spyder/plugins/ipythonconsole/widgets/main_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
ClientContextMenuActions,
IPythonConsoleWidgetActions,
IPythonConsoleWidgetMenus,
IPythonConsoleWidgetCornerWidgets,
IPythonConsoleWidgetOptionsMenuSections,
IPythonConsoleWidgetTabsContextMenuSections
)
Expand Down Expand Up @@ -620,25 +621,28 @@ def setup(self):

# --- Widgets for the tab corner
self.reset_button = self.create_toolbutton(
'reset',
IPythonConsoleWidgetCornerWidgets.ResetButton,
text=_("Remove all variables"),
tip=_("Remove all variables from kernel namespace"),
tip=_("Remove all variables from namespace"),
icon=self.create_icon("editdelete"),
triggered=self.reset_namespace,
)
self.stop_button = self.create_toolbutton(
'interrupt',
IPythonConsoleWidgetCornerWidgets.InterruptButton,
text=_("Interrupt kernel"),
tip=_("Interrupt kernel"),
icon=self.create_icon('stop'),
triggered=self.interrupt_kernel,
)
self.time_label = QLabel("")
self.time_label.name = (
IPythonConsoleWidgetCornerWidgets.TimeElapsedLabel
)

# --- Add tab corner widgets.
self.add_corner_widget('timer', self.time_label)
self.add_corner_widget('reset', self.reset_button)
self.add_corner_widget('start_interrupt', self.stop_button)
self.add_corner_widget(self.stop_button)
self.add_corner_widget(self.reset_button)
self.add_corner_widget(self.time_label)

# --- Tabs context menu
tabs_context_menu = self.create_menu(
Expand Down
16 changes: 7 additions & 9 deletions spyder/plugins/variableexplorer/widgets/main_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,18 +447,16 @@ def _setup(self):
toggled=self._enable_filter_actions,
option='filter_on',
tip=_("Filter variables")
)
)
self.filter_button.setCheckable(True)
self.filter_button.toggled.connect(self._set_filter_button_state)

corner_widget = self._corner_widget
for action in corner_widget.actions():
if action.defaultWidget() == self.get_options_menu_button():
options_menu_action = action

for action in [self.search_action, self.filter_button,
self.refresh_action]:
corner_widget.insertAction(options_menu_action, action)
for action in [
self.search_action,
self.filter_button,
self.refresh_action,
]:
self.add_corner_widget(action, before=self._options_button)

def update_actions(self):
"""Update the actions."""
Expand Down
4 changes: 3 additions & 1 deletion spyder/utils/qthelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ def create_toolbutton(parent, text=None, shortcut=None, icon=None, tip=None,
return button


def create_waitspinner(size=32, n=11, parent=None):
def create_waitspinner(size=32, n=11, parent=None, name=None):
"""
Create a wait spinner with the specified size built with n circling dots.
"""
Expand All @@ -314,6 +314,8 @@ def create_waitspinner(size=32, n=11, parent=None):
spinner.setInnerRadius(inner_radius)
spinner.setColor(SpyderPalette.COLOR_TEXT_1)

spinner.name = name

return spinner


Expand Down

0 comments on commit 0f6b0b3

Please sign in to comment.