Skip to content

Commit

Permalink
OWWidget: Collapse/expand the widget on control area toggle
Browse files Browse the repository at this point in the history
  • Loading branch information
ales-erjavec committed Jul 20, 2018
1 parent 371a193 commit 97a007c
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 30 deletions.
3 changes: 1 addition & 2 deletions Orange/widgets/tests/test_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,7 @@ class Widget(OWWidget):
want_control_area = True

w = Widget()
splitter = w._OWWidget__splitter # type: OWWidget._Splitter
splitter.setControlAreaVisible(False)
w._OWWidget__setControlAreaVisible(False)
w.setGeometry(QRect(51, 52, 53, 54))
state = w.saveGeometryAndLayoutState()
w1 = Widget()
Expand Down
100 changes: 72 additions & 28 deletions Orange/widgets/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
from AnyQt.QtWidgets import (
QWidget, QDialog, QVBoxLayout, QSizePolicy, QApplication, QStyle,
QShortcut, QSplitter, QSplitterHandle, QPushButton, QStatusBar,
QProgressBar, QAction
QProgressBar, QAction, QWIDGETSIZE_MAX
)
from AnyQt.QtCore import (
Qt, QByteArray, QDataStream, QBuffer, QSettings, QUrl, pyqtSignal as Signal
Qt, QRect, QMargins, QByteArray, QDataStream, QBuffer, QSettings,
QUrl, pyqtSignal as Signal
)
from AnyQt.QtGui import QIcon, QKeySequence, QDesktopServices

Expand Down Expand Up @@ -235,12 +236,13 @@ def __new__(cls, *args, captionTitle=None, **kwargs):
self.controlArea.setFocus(Qt.ActiveWindowFocusReason)

if self.__splitter is not None:
self.__splitter.controlAreaVisibilityChanged.connect(
self.storeControlAreaVisibility)
self.__splitter.handleClicked.connect(
self.__toggleControlArea
)
sc = QShortcut(
QKeySequence(Qt.ControlModifier | Qt.ShiftModifier | Qt.Key_D),
self)
sc.activated.connect(self.__splitter.flip)
sc.activated.connect(self.__toggleControlArea)
return self

# pylint: disable=super-init-not-called
Expand Down Expand Up @@ -268,8 +270,7 @@ def get_flags(cls):
else Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint)

class _Splitter(QSplitter):
controlAreaVisibilityChanged = Signal(int)

handleClicked = Signal()
def _adjusted_size(self, size_method):
size = size_method(super())()
height = max((size_method(self.widget(i))().height()
Expand All @@ -289,26 +290,11 @@ def createHandle(self):
return self._Handle(
self.orientation(), self, cursor=Qt.PointingHandCursor)

def flip(self):
if self.count() == 1: # Prevent hiding control area by shortcut
return
self.setControlAreaVisible(not self.controlAreaVisible())

def setControlAreaVisible(self, visible):
if self.controlAreaVisible() == visible:
return
self.setSizes([int(visible), 100000])
self.controlAreaVisibilityChanged.emit(visible)
self.updateGeometry()

def controlAreaVisible(self):
return bool(self.sizes()[0])

class _Handle(QSplitterHandle):
def mouseReleaseEvent(self, event):
"""Resize on left button"""
if event.button() == Qt.LeftButton:
self.splitter().flip()
self.splitter().handleClicked.emit()
super().mouseReleaseEvent(event)

def mouseMoveEvent(self, event):
Expand Down Expand Up @@ -458,6 +444,67 @@ def _(val):
margins.setBottom(sb.sizeHint().height())
self.setContentsMargins(margins)

def __toggleControlArea(self):
if self.__splitter is None or self.__splitter.count() < 2:
return
self.__setControlAreaVisible(not self.__splitter.sizes()[0])

def __setControlAreaVisible(self, visible):
# type: (bool) -> None
if self.__splitter is None or self.__splitter.count() < 2:
return
self.controlAreaVisible = visible
splitter = self.__splitter # type: QSplitter
w = splitter.widget(0)
sizes = splitter.sizes()
current_size = sizes[0]

if bool(current_size) == visible:
return

current_width = w.width()
geom = self.geometry()
frame = self.frameGeometry()
framemargins = QMargins(
frame.left() - geom.left(),
frame.top() - geom.top(),
frame.right() - geom.right(),
frame.bottom() - geom.bottom()
)
splitter.setSizes([int(visible), QWIDGETSIZE_MAX])
if not self.isWindow() or \
self.windowState() not in {Qt.WindowNoState, Qt.WindowActive}:
# not a window or not in state where we can move move/resize
return

# force immediate resize recalculation
splitter.refresh()
self.layout().invalidate()
self.layout().activate()

if visible:
# move left and expand by the exposing widget's width
diffx = -w.width()
diffw = w.width()
else:
# move right and shrink by the collapsing width
diffx = current_width
diffw = -current_width
newgeom = QRect(
geom.x() + diffx, geom.y(), geom.width() + diffw, geom.height()
)
# bound/move by available geometry
bounds = QApplication.desktop().availableGeometry(self)
bounds = bounds.adjusted(
framemargins.left(), framemargins.top(),
-framemargins.right(), -framemargins.bottom()
)
newsize = newgeom.size().boundedTo(bounds.size())
newgeom = QRect(newgeom.topLeft(), newsize)
newgeom.moveLeft(max(newgeom.left(), bounds.left()))
newgeom.moveRight(min(newgeom.right(), bounds.right()))
self.setGeometry(newgeom)

def save_graph(self):
"""Save the graph with the name given in class attribute `graph_name`.
Expand All @@ -476,9 +523,6 @@ def copy_to_clipboard(self):
return
ClipboardFormat.write_image(None, graph_obj)

def storeControlAreaVisibility(self, visible):
self.controlAreaVisible = visible

def __restoreWidgetGeometry(self, geometry):
# type: (bytes) -> bool
def _fullscreen_to_maximized(geometry):
Expand Down Expand Up @@ -577,7 +621,7 @@ def showEvent(self, event):
if self.save_position and not self.__was_restored:
# Restore saved geometry on (first) show
if self.__splitter is not None:
self.__splitter.setControlAreaVisible(self.controlAreaVisible)
self.__setControlAreaVisible(self.controlAreaVisible)
if self.savedWidgetGeometry is not None:
self.__restoreWidgetGeometry(bytes(self.savedWidgetGeometry))
self.__was_restored = True
Expand Down Expand Up @@ -824,7 +868,7 @@ def restoreGeometryAndLayoutState(self, state):
has_spliter = splitter_state & 0x2
splitter_state = splitter_state & 0x1
if has_spliter and self.__splitter is not None:
self.__splitter.setControlAreaVisible(bool(splitter_state))
self.__setControlAreaVisible(bool(splitter_state))
geometry = QByteArray()
stream >> geometry
if stream.status() == QDataStream.Ok:
Expand Down

0 comments on commit 97a007c

Please sign in to comment.