Skip to content

Commit

Permalink
Fixes issue #139 - Live profile mouse interaction feature and subsequ…
Browse files Browse the repository at this point in the history
…ent dockable widget fixes.
  • Loading branch information
razman786 committed Jun 6, 2022
1 parent 286f124 commit 26d80dc
Show file tree
Hide file tree
Showing 5 changed files with 345 additions and 110 deletions.
74 changes: 24 additions & 50 deletions TigGUI/Images/Controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def __init__(self, image, parent, imgman, name=None, save=False):
self._currier.curry(self.image.signalCenter.emit, True))
self._qa_show_rc = self._menu.addAction(pixmaps.colours.icon(), "Colours && Intensities...",
self.showRenderControls)
self._qa_wcs = self._menu.addAction(pixmaps.wcs_image.icon(), "Information", self._viewWCS)
self._qa_wcs = self._menu.addAction(pixmaps.wcs_image.icon(), "Information", self._viewWCS, shortcut=Qt.Key_F5)
if save:
self._qa_save = self._menu.addAction("Save image...", self._saveImage)
self._menu.addAction("Export image to PNG file...", self._exportImageToPNG)
Expand Down Expand Up @@ -345,103 +345,77 @@ def showRenderControls(self):
bind_widget=self._control_dialog,
close_slot=self.colourctrl_dockwidget_closed,
toggle_slot=self.colourctrl_dockwidget_toggled)
self.addDockWidgetToTab()
self.parent().mainwin.addDockWidgetToArea(self._dockable_colour_ctrl, 2)
dprint(1, "done")
# set dockable widget visibility in sync with control dialog
if not self._control_dialog.isVisible():
dprint(1, "showing control dialog")
self._control_dialog.show()
if self._dockable_colour_ctrl is not None:
self._dockable_colour_ctrl.setVisible(True)
self.addDockWidgetToTab()
self.parent().mainwin.addDockWidgetToArea(self._dockable_colour_ctrl, 2)
self._dockable_colour_ctrl.show()
self._dockable_colour_ctrl.raise_()
if not self.get_docked_widget_size(self._dockable_colour_ctrl):
if not self.get_docked_widget_size(self._dockable_colour_ctrl, 2):
self.expand_mainwindow_dockable(self._dockable_colour_ctrl)
else:
self._control_dialog.hide()
self._dockable_colour_ctrl.setVisible(False)
if not self.get_docked_widget_size(self._dockable_colour_ctrl):
if not self.get_docked_widget_size(self._dockable_colour_ctrl, 2):
self.shrink_mainwindow_dockable(self._dockable_colour_ctrl)

def addDockWidgetToTab(self):
# Add dockable widget to main window.
# This needs to itterate through the widgets to find DockWidgets already in the right side area,
# then tabifydockwidget when adding, or add to the right area if empty
widget_list = self.parent().mainwin.findChildren(QDockWidget)
for widget in widget_list:
if self.parent().mainwin.dockWidgetArea(widget) == 2: # if in right dock area
if widget.isVisible() and not widget.isFloating(): # if widget active and not a window
if self._dockable_colour_ctrl is not widget: # check not itself
# add dock widget in tab on top of current widget in right area
self.parent().mainwin.tabifyDockWidget(widget, self._dockable_colour_ctrl)
self.parent().mainwin.resizeDocks([widget], [widget.bind_widget.width()], Qt.Horizontal)
elif self.parent().mainwin.dockWidgetArea(
widget) == 0: # if not in any dock area assume we have new dock widget
# no previous widget in this area then add
self.parent().mainwin.addDockWidget(Qt.RightDockWidgetArea, self._dockable_colour_ctrl)
self.parent().mainwin.resizeDocks([widget], [widget.bind_widget.width()], Qt.Horizontal)

def removeDockWidget(self):
# remove image control dock widget
self.parent().mainwin.removeDockWidget(self._dockable_colour_ctrl)
# get widgets to resize
widget_list = self.parent().mainwin.findChildren(QDockWidget)
size_list = []
result = []
for widget in widget_list:
if not isinstance(widget.bind_widget, ImageControlDialog):
size_list.append(widget.bind_widget.width())
result.append(widget)
dprint(2, f"{widget} width {widget.width()}")
dprint(2, f"{widget} bind_widget width {widget.bind_widget.width()}")
if isinstance(widget.bind_widget, LiveImageZoom):
widget.bind_widget.setMinimumWidth(widget.width())
widget_list = result
# resize dock areas
self.parent().mainwin.resizeDocks(widget_list, size_list, Qt.Horizontal)
self.parent().mainwin.restoreDockArea(2)

def colourctrl_dockwidget_closed(self):
self._dockable_colour_ctrl.setVisible(False)
if self.parent().mainwin.windowState() != Qt.WindowMaximized:
if not self.get_docked_widget_size(self._dockable_colour_ctrl):
if not self.get_docked_widget_size(self._dockable_colour_ctrl, 2):
if not self._dockable_colour_ctrl.isFloating():
geo = self.parent().mainwin.geometry()
geo.setWidth(self.parent().mainwin.width() - self._dockable_colour_ctrl.width())
geo.setWidth(self.parent().mainwin.width() -
self._dockable_colour_ctrl.width())
self.parent().mainwin.setGeometry(geo)
self.parent().mainwin.restoreDockArea(2)

def colourctrl_dockwidget_toggled(self):
if not self._dockable_colour_ctrl.isVisible():
return
if self._dockable_colour_ctrl.isWindow():
self._dockable_colour_ctrl.setFloating(False)
if self.parent().mainwin.windowState() != Qt.WindowMaximized:
if not self.get_docked_widget_size(self._dockable_colour_ctrl):
if not self.get_docked_widget_size(self._dockable_colour_ctrl, 2):
self.expand_mainwindow_dockable(self._dockable_colour_ctrl)
self.parent().mainwin.addDockWidgetToArea(self._dockable_colour_ctrl, 2)
else:
self._dockable_colour_ctrl.setFloating(True)
if self.parent().mainwin.windowState() != Qt.WindowMaximized:
if not self.get_docked_widget_size(self._dockable_colour_ctrl):
if not self.get_docked_widget_size(self._dockable_colour_ctrl, 2):
self.shrink_mainwindow_dockable(self._dockable_colour_ctrl)
self.parent().mainwin.restoreDockArea(2)

def shrink_mainwindow_dockable(self, _dockable):
geo = self.parent().mainwin.geometry()
geo.setWidth(self.parent().mainwin.width() - _dockable.width())
self.parent().mainwin.setGeometry(geo)
self._resize_mainwindow_docked_widgets(geo, _dockable)

def expand_mainwindow_dockable(self, _dockable):
geo = self.parent().mainwin.geometry()
geo.setWidth(self.parent().mainwin.width() + _dockable.width())
self._resize_mainwindow_docked_widgets(geo, _dockable)

def _resize_mainwindow_docked_widgets(self, geo, _dockable):
self.parent().mainwin.setGeometry(geo)
_area = self.parent().mainwin.dockWidgetArea(_dockable)
self.parent().mainwin.resize_docked_widgets(_area)

def get_docked_widget_size(self, _dockable):
def get_docked_widget_size(self, _dockable, _area):
widget_list = self.parent().mainwin.findChildren(QDockWidget)
size_list = []
if _dockable:
for widget in widget_list:
if isinstance(widget.bind_widget, ImageControlDialog):
if self.parent().mainwin.dockWidgetArea(widget) == _area:
if widget is not _dockable:
if not widget.isWindow() and not widget.isFloating() and widget.isVisible():
if (not widget.isWindow() and not widget.isFloating()
and widget.isVisible()):
size_list.append(widget.bind_widget.width())
if size_list:
return max(size_list)
Expand Down
120 changes: 115 additions & 5 deletions TigGUI/MainWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
from Tigger.Models import SkyModel
import Tigger.Models.Formats
from Tigger.Models.Formats import ModelHTML
from astropy.io.fits.hdu import base

QStringList = list

Expand Down Expand Up @@ -78,6 +79,7 @@ def __init__(self, parent, max_width=None, max_height=None, hide_on_close=False)
self.setWindowIcon(QIcon(pixmaps.purr_logo.pm()))
# central widget setup
self.cw = QWidget(self)
self.cw.setContentsMargins(10, 10, 10, 10)
# The actual min width of the control dialog is ~396
self._ctrl_dialog_min_size = 400 # approx value
# The actual min width of the profile/zoom windows is ~256
Expand All @@ -101,21 +103,21 @@ def __init__(self, parent, max_width=None, max_height=None, hide_on_close=False)
spl2.setOpaqueResize(False)
self._skyplot_stack = QWidget(spl2)
self._skyplot_stack_lo = QVBoxLayout(self._skyplot_stack)
self._skyplot_stack_lo.setContentsMargins(0, 0, 0, 0)
self._skyplot_stack_lo.setContentsMargins(5, 5, 5, 5)

# add plot
self.skyplot = SkyModelPlotter(self._skyplot_stack, self)
self.skyplot.resize(128, 128)
self.skyplot.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
self._skyplot_stack_lo.addWidget(self.skyplot, 1000)
self.skyplot.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
self._skyplot_stack_lo.addWidget(self.skyplot)
self.skyplot.hide()
self.skyplot.imagesChanged.connect(self._imagesChanged)
self.skyplot.setupShowMessages(self.signalShowMessage)
self.skyplot.setupShowErrorMessages(self.signalShowErrorMessage)

self._grouptab_stack = QWidget(spl2)
self._grouptab_stack_lo = lo = QVBoxLayout(self._grouptab_stack)
self._grouptab_stack_lo.setContentsMargins(0, 0, 0, 0)
self._grouptab_stack_lo.setContentsMargins(5, 5, 5, 5)
# add groupings table
self.grouptab = ModelGroupsTable(self._grouptab_stack)
self.grouptab.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
Expand Down Expand Up @@ -324,11 +326,15 @@ def setLayout(self, layout):
if Config.getbool('livezoom-show'):
self.skyplot._livezoom.setVisible(True)
self.skyplot._dockable_livezoom.setVisible(True)
self.addDockWidget(Qt.LeftDockWidgetArea, self.skyplot._dockable_livezoom)
self.addDockWidget(Qt.RightDockWidgetArea, self.skyplot._dockable_livezoom)
if Config.getbool('liveprofile-show'):
self.skyplot._liveprofile.setVisible(True)
self.skyplot._dockable_liveprofile.setVisible(True)
self.addDockWidget(Qt.LeftDockWidgetArea, self.skyplot._dockable_liveprofile)
if Config.getbool('liveprofileselected-show'):
self.skyplot._liveprofile_selected.setVisible(True)
self.skyplot._dockable_liveprofile_selected.setVisible(True)
self.addDockWidget(Qt.LeftDockWidgetArea, self.skyplot._dockable_liveprofile_selected)
# resize dock areas
widget_list = self.findChildren(QDockWidget)
size_list = []
Expand Down Expand Up @@ -779,3 +785,107 @@ def _indicateModelUpdated(self, what=None, origin=None, updated=True):
if self.model:
self.setWindowTitle(
"Tigger - %s%s" % ((self._display_filename or "(unnamed)", " (modified)" if updated else "")))

def restoreDockArea(self, _area):
"""Restores the dockable area and untabs dockables if possible."""
_dockarea = []
widget_list = self.findChildren(QDockWidget)
for widget in widget_list:
if self.dockWidgetArea(widget) == _area:
if widget.isVisible() and not widget.isFloating():
if _area == 2:
if isinstance(widget.bind_widget, ImageControlDialog):
# or isinstance(widget.bind_widget, LiveImageZoom):
_dockarea = []
break
_dockarea.append(widget)
if len(_dockarea) > 1:
for widget in _dockarea:
self.removeDockWidget(widget)
self.addDockWidget(_area, widget)
widget.setVisible(True)
self.resize_docked_widgets(_area)

def addDockWidgetToArea(self, _dockable, _area):
"""Add a dockable widget to a dock area in the main window. If other dockable widgets are
in place then it will tab the dockables together."""
# This needs to itterate through the widgets to find DockWidgets already in the area,
# then tabifydockwidget when adding, or add to the area if empty
# Find all dockwidgets in the related area
_dockarea = []
widget_list = self.findChildren(QDockWidget)
for widget in widget_list:
if self.dockWidgetArea(widget) == _area:
if widget.isVisible() and not widget.isFloating():
if _dockable is not widget: # check not itself
# Add dock widget to list
_dockarea.append(widget)
# From the dockwidgets found check which widgets are tabbed
tabbed_in_area = []
for widget in _dockarea:
_w = self.tabifiedDockWidgets(widget)
if _w:
tabbed_in_area = tabbed_in_area + _w
if tabbed_in_area:
tabbed_in_area = list(dict.fromkeys(tabbed_in_area))
dprint(2, f"tabbed dockables {tabbed_in_area}, dockables from area {_area}, {_dockarea}")
# If widgegts that are not tabbed, tab them and then add the new dockable
if not tabbed_in_area and _dockarea:
# Tabify dockables before adding
if len(_dockarea) > 1:
base_widget = _dockarea.pop()
for widget in _dockarea:
self.tabifyDockWidget(base_widget, widget)
self.resizeDocks([base_widget, widget],
[base_widget.bind_widget.width(), widget.bind_widget.width()],
Qt.Horizontal)
# Add dockable after tabifying
self.tabifyDockWidget(base_widget, _dockable)
else:
if isinstance(_dockarea[-1].bind_widget, ImageControlDialog):
self.tabifyDockWidget(_dockarea[-1], _dockable)
else:
# No need to tabify as there is only 1 other dockable
self.addDockWidget(_area, _dockable)
# If already tabbed just tabify
elif tabbed_in_area and not _dockarea:
self.tabifyDockWidget(tabbed_in_area[-1], _dockable)
# If a mixture of tabbed and untabbed - organise
elif tabbed_in_area and _dockarea:
# If equal the all are tabbed
if tabbed_in_area == _dockarea:
self.tabifyDockWidget(tabbed_in_area[-1], _dockable)
else:
# Get all that are not tabbed
wdiff = set(_dockarea) - set(tabbed_in_area)
# Tabify if only one
if wdiff and len(wdiff) == 1:
self.tabifyDockWidget(list(wdiff)[-1], _dockable)
# If more then tabify all before adding dockable
elif wdiff and len(wdiff) > 1:
wdiff = list(wdiff)
base_widget = wdiff.pop()
for widget in wdiff:
self.tabifyDockWidget(base_widget, widget)
self.resizeDocks([base_widget, widget],
[base_widget.bind_widget.width(), widget.bind_widget.width()],
Qt.Horizontal)
# Add dockable after tabifying
self.tabifyDockWidget(base_widget, _dockable)
# If no other dockables found
elif not tabbed_in_area and not _dockarea:
self.addDockWidget(_area, _dockable)
# Resize dockables in this area
self.resize_docked_widgets(_area)

def resize_docked_widgets(self, _area):
"""Resize dockables within a given dock widget area."""
size_list = []
resize_list = []
widget_list = self.findChildren(QDockWidget)
for widget in widget_list:
if self.dockWidgetArea(widget) == _area:
if widget.isVisible() and not widget.isFloating():
resize_list.append(widget)
size_list.append(widget.bind_widget.width())
self.resizeDocks(resize_list, size_list, Qt.Horizontal)
Loading

0 comments on commit 26d80dc

Please sign in to comment.