Skip to content

Work around infinite recursion in ToolPalette.resizeEvent() #76

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 8, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 51 additions & 16 deletions labscript_utils/qtwidgets/toolpalette.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
EXPAND_ICON = ':/qtutils/fugue/toggle-small-expand'
CONTRACT_ICON = ':/qtutils/fugue/toggle-small'

_ENABLE_LAYOUT_EVENT_TYPE = QEvent.User

class ToolPaletteGroup(QVBoxLayout):

def __init__(self,*args,**kwargs):
Expand Down Expand Up @@ -265,6 +267,10 @@ def __init__(self,parent,name,*args,**kwargs):
self._column_count = 0
self._row_count = 0

# Variable for controlling whether or not self._layout_widgets() is
# called in self.resizeEvent().
self._layout_widgets_during_resizeEvent = True

def addWidget(self,widget,force_relayout=True):
# Append to end of tool pallete
#widget.clicked.connect(embed)
Expand Down Expand Up @@ -385,24 +391,53 @@ def minimumSizeHint(self):
height = self.minimumSize().height()
return QSize(width, height)

def event(self, event):
# Handle the custom event for reenabling the call to
# self._layout_widgets() during self.resizeEvent().
if (event.type() == _ENABLE_LAYOUT_EVENT_TYPE):
self._layout_widgets_during_resizeEvent = True
# Return True so that this event isn't sent along to other event
# handlers as well.
return True

# Handle all other events in the usual way.
return super().event(event)

def resizeEvent(self, event):
# overwrite the resize event!
# print '--------- %s'%self._name
# print self._widget_list[0].size()
# print self._widget_list[0].sizeHint()
# print self._widget_list[0].minimumSizeHint()
# print self._layout.rowMinimumHeight(0)
# print self.size()
# print self.minimumSize()
# print self.sizeHint()
# print self.minimumSizeHint()
#pass resize event on to qwidget
# call layout()
QWidget.resizeEvent(self, event)
size = event.size()
if size.width() == self.size().width() and size.height() == self.size().height():
# print 'relaying out widgets'
self._layout_widgets()
# This method can end up undergoing infinite recursion for some window
# layouts, see
# https://github.com/labscript-suite/labscript-utils/issues/27. It seems
# that sometimes self._layout_widgets() increases the number of columns,
# which then triggers a resizeEvent, which then calls
# self._layout_widgets() which then decreases the number of columns to
# its previous value, which triggers a resizeEvent, and so on. That loop
# may occur e.g. if increasing/decreasing the number of columns
# add/removes a scrollbar, which then changes the number of widgets that
# can fit in a row. Keeping track of the recursion depth isn't trivial
# because _layout_widgets() doesn't directly call itself; it just causes
# more resizing events to be added to the event queue. To work around
# that, this method will mark that future calls to this method shouldn't
# call _layout_widgets() but will also add an event to the event queue
# to reenable calling _layout_widgets() again once all of the resize
# events caused by this call to it have been processed.

try:
#pass resize event on to qwidget
QWidget.resizeEvent(self, event)
size = event.size()
if size.width() == self.size().width() and size.height() == self.size().height():
if self._layout_widgets_during_resizeEvent:
# Avoid calling this again until all the resize events that
# will be put in the queue by self._layout_widgets() have
# run.
self._layout_widgets_during_resizeEvent = False
self._layout_widgets()
finally:
# Add event to end of the event queue to allow _layout_widgets() in
# future calls. This event shouldn't be handled until the resize
# events generated during _layout_widgets() have run.
QCoreApplication.instance().postEvent(self, QEvent(_ENABLE_LAYOUT_EVENT_TYPE))


# A simple test!
Expand Down