Skip to content

Commit

Permalink
Merge pull request #469 from nucleic/dock-area-fixes
Browse files Browse the repository at this point in the history
Dock area fixes
  • Loading branch information
MatthieuDartiailh committed Jan 28, 2022
2 parents e9e1f30 + 72db305 commit 5be91cd
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 21 deletions.
5 changes: 5 additions & 0 deletions enaml/qt/docking/dock_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ def close_window(self, window, event):
size = container.sizeHint()
geometries[container] = QRect(window.pos(), size)
for container in containers:
# Return a maximized container to normal.
# This ensures the container is properly removed from all the
# layouts it is attached to and it ca be freed once closed.
if container.frame_state.item_is_maximized:
container.showNormal()
if not container.close():
container.unplug()
container.float()
Expand Down
7 changes: 7 additions & 0 deletions enaml/qt/docking/q_dock_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from enaml.qt.QtCore import Qt, QMargins, QPoint, QRect, QEvent, Signal
from enaml.qt.QtGui import QIcon, QCursor
from enaml.qt.QtWidgets import QApplication, QLayout
from enaml.qt.docking.q_dock_window import QDockWindow

from .event_types import QDockItemEvent, DockItemUndocked
from .q_dock_area import QDockArea
Expand Down Expand Up @@ -595,8 +596,14 @@ def onPinButtonToggled(self, pinned):
if pinned:
if not self.frame_state.in_dock_bar:
position = _closestDockBar(self)
parent_is_floating = isinstance(area.parent(), QDockWindow)
# Do not close a floating window when pinning the last item.
if parent_is_floating:
area.parent().frame_state.in_pin_event = True
self.unplug()
area.addToDockBar(self, position)
if parent_is_floating:
area.parent().frame_state.in_pin_event = False
else:
position = area.dockBarPosition(self)
if position is not None:
Expand Down
8 changes: 4 additions & 4 deletions enaml/qt/docking/q_dock_placeholder.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ def __init__(self, widget):
self.widget = widget
if isinstance(parent, QSplitter):
index = parent.indexOf(widget)
layout = parent
parent.replaceWidget(index, self)
else:
index = 0
layout = parent.layout()
layout.replaceWidget(index, self)
layout.replaceWidget(widget, self)
widget.hide()

def restore(self):
Expand All @@ -36,11 +36,11 @@ def restore(self):
widget = self.widget
if isinstance(parent, QSplitter):
index = parent.indexOf(self)
layout = parent
parent.replaceWidget(index, widget)
else:
index = 0
layout = parent.layout()
layout.replaceWidget(index, widget)
layout.replaceWidget(self, widget)
widget.show()

def getPlaceholder(self):
Expand Down
38 changes: 30 additions & 8 deletions enaml/qt/docking/q_dock_tab_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from enaml.qt.qt_menu import QCustomMenu

from .event_types import QDockItemEvent, DockTabSelected
from .q_dock_area import QDockArea
from .q_bitmap_button import QBitmapButton
from .q_dock_title_bar import QDockTitleBar
from .q_dock_placeholder import QDockPlaceholder
Expand Down Expand Up @@ -261,6 +262,9 @@ def tabInserted(self, index):
self.setCloseButtonVisible(index, container.closable())
self._tab_data.insert(index, _TabData(container))

# Update the visibility of the close button on the overall tab.
self.parent().setGlobalCloseButtonVisible()

def tabRemoved(self, index):
""" Handle a tab removal from the tab bar.
Expand All @@ -273,6 +277,9 @@ def tabRemoved(self, index):
if container is not None:
container.alerted.disconnect(self._onAlerted)

# Update the visibility of the close button on the overall tab.
self.parent().setGlobalCloseButtonVisible()

def mousePressEvent(self, event):
""" Handle the mouse press event for the tab bar.
Expand Down Expand Up @@ -417,16 +424,20 @@ def __init__(self, parent=None):
# Private API
#--------------------------------------------------------------------------
def parentDockArea(self):
""" Return the parent dock area if any.
""" Get the parent dock area of the container.
Returns
-------
result : QDockArea or None
The nearest ancestor which is an instance of QDockArea, or
None if no such ancestor exists.
"""
container = self.widget(0)
if container is None:
return
manager = container.manager()
if manager is None:
return
return manager.dock_area()
parent = self.parent()
while parent is not None:
if isinstance(parent, QDockArea):
return parent
parent = parent.parent()

def _onTabCloseRequested(self, index):
""" Handle the close request for the given tab index.
Expand Down Expand Up @@ -567,3 +578,14 @@ def setCloseButtonVisible(self, index, visible):
"""
self.tabBar().setCloseButtonVisible(index, visible)

def setGlobalCloseButtonVisible(self):
"""Set the visibility of the global tab close button."""

corner_widget = self.cornerWidget()
buttons = (QDockTitleBar.MaximizeButton | QDockTitleBar.TabsButton)
# Update visibility of the close button, we hide the button if no tab is
# closable.
if any(self.widget(i).closable() for i in range(self.count())):
buttons |= QDockTitleBar.CloseButton
corner_widget.setButtons(buttons)
10 changes: 8 additions & 2 deletions enaml/qt/docking/q_dock_title_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,14 @@ def __init__(self, parent=None):
link_button.setCheckedBitmap(LINKED_BUTTON.toBitmap())
link_button.setIconSize(btn_size)
link_button.setVisible(self._buttons & self.LinkButton)
link_button.setToolTip('Link Window')
link_button.setCheckedToolTip('Unlink Window')
link_button.setToolTip(
'Link Window\n\n'
'Floating windows snapped together move together when they are linked.'
)
link_button.setCheckedToolTip(
'Unlink Window\n\n'
'Floating windows snapped together move together when they are linked.'
)

pin_button = self._pin_button = QCheckedBitmapButton(self)
pin_button.setObjectName('docktitlebar-pin-button')
Expand Down
19 changes: 16 additions & 3 deletions enaml/qt/docking/q_dock_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,14 @@ def __init__(self, parent=None):
link_button.setCheckedBitmap(LINKED_BUTTON.toBitmap())
link_button.setIconSize(QSize(20, 15))
link_button.setVisible(self._buttons & self.LinkButton)
link_button.setToolTip('Link Window')
link_button.setCheckedToolTip('Unlink Window')
link_button.setToolTip(
'Link Window\n\n'
'Floating windows snapped together move together when they are linked.'
)
link_button.setCheckedToolTip(
'Unlink Window\n\n'
'Floating windows snapped together move together when they are linked.'
)

layout = QHBoxLayout()
layout.setContentsMargins(QMargins(0, 0, 0, 0))
Expand Down Expand Up @@ -192,6 +198,9 @@ class FrameState(QDockFrame.FrameState):
#: Whether or not the window is being dragged by the user.
dragging = Bool(False)

#: Whether a dock item is in the process of being pinned.
in_pin_event = Bool(False)

#: Whether the window is inside it's close event.
in_close_event = Bool(False)

Expand Down Expand Up @@ -359,7 +368,11 @@ def eventFilter(self, area, event):
will close the window when the dock area is empty.
"""
if event.type() == DockAreaContentsChanged and area.isEmpty():
if (
event.type() == DockAreaContentsChanged
and not self.frame_state.in_pin_event
and area.isEmpty()
):
# Hide the window so that it doesn't steal events from
# the floating window when this window is closed.
self.hide()
Expand Down
3 changes: 2 additions & 1 deletion enaml/qt/qt_dock_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from .docking.q_dock_item import QDockItem

from .q_deferred_caller import deferredCall
from .q_resource_helpers import get_cached_qicon
from .qt_widget import QtWidget
from .styleutil import translate_dock_item_style
Expand Down Expand Up @@ -175,7 +176,7 @@ def on_closed(self):
"""
d = self.declaration
if d is not None:
d._item_closed()
deferredCall(d._item_closed)

#--------------------------------------------------------------------------
# Child Events
Expand Down
5 changes: 4 additions & 1 deletion enaml/widgets/dock_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ def _update_proxy(self, change):
def _item_closed(self):
""" Called by the proxy when the toolkit item is closed.
This is performed as a deferred call so that the window may fully
close before the declaration is potentially destroyed.
"""
self.closed()
deferred_call(self.destroy)
self.destroy()
1 change: 1 addition & 0 deletions examples/widgets/dock_area.enaml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ enamldef MyDockArea(DockArea):
DockItem:
name = 'logger'
title = 'Logger'
closable = False
Container:
MultilineField:
attr collector = LineCollector()
Expand Down
5 changes: 3 additions & 2 deletions releasenotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ Dates are written as DD/MM/YYYY

0.15.0 - Unreleased
-------------------
- Add python fstring scintilla tokens PR #470
- Address PyQt deprecation of accepting float values for pixel dimensions PR #471
- fixes several bugs in corner cases of the Qt dock area PR #469
- add python fstring scintilla tokens PR #470
- address PyQt deprecation of accepting float values for pixel dimensions PR #471

0.14.0 - 21/11/2021
-------------------
Expand Down

0 comments on commit 5be91cd

Please sign in to comment.