Skip to content

Commit

Permalink
Merge pull request #74 from nucleic/stack-size-hints
Browse files Browse the repository at this point in the history
add a mode to use the size hint from the current item
  • Loading branch information
sccolbert committed Oct 26, 2013
2 parents 0a08057 + e081963 commit 330c7a3
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 7 deletions.
113 changes: 110 additions & 3 deletions enaml/qt/qt_notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
import sys
from weakref import WeakKeyDictionary

from atom.api import Int, Typed
from atom.api import Int, IntEnum, Typed

from enaml.widgets.notebook import ProxyNotebook

from .QtCore import Qt, QEvent, Signal
from .QtGui import QTabWidget, QTabBar, QResizeEvent, QApplication
from .QtCore import Qt, QEvent, QSize, Signal
from .QtGui import (
QTabWidget, QTabBar, QResizeEvent, QApplication, QStackedWidget
)

from .qt_constraints_widget import QtConstraintsWidget
from .qt_page import QtPage
Expand All @@ -37,6 +39,20 @@ class QNotebook(QTabWidget):
""" A custom QTabWidget which handles children of type QPage.
"""
class SizeHintMode(IntEnum):
""" An int enum defining the size hint modes of the notebook.
"""
#: The size hint is the union of all tabs.
Union = 0

#: The size hint is the size hint of the current tab.
Current = 1

#: Proxy the SizeHintMode values as if it were an anonymous enum.
Union = SizeHintMode.Union
Current = SizeHintMode.Current

#: A signal emitted when a LayoutRequest event is posted to the
#: notebook widget. This will typically occur when the size hint
#: of the notebook is no longer valid.
Expand All @@ -55,6 +71,9 @@ def __init__(self, *args, **kwargs):
super(QNotebook, self).__init__(*args, **kwargs)
self.tabCloseRequested.connect(self.onTabCloseRequested)
self._hidden_pages = WeakKeyDictionary()
self._size_hint = QSize()
self._min_size_hint = QSize()
self._size_hint_mode = QNotebook.Union

#--------------------------------------------------------------------------
# Private API
Expand Down Expand Up @@ -101,9 +120,81 @@ def event(self, event):
"""
res = super(QNotebook, self).event(event)
if event.type() == QEvent.LayoutRequest:
self._size_hint = QSize()
self._min_size_hint = QSize()
self.layoutRequested.emit()
return res

def sizeHint(self):
""" A reimplemented size hint handler.
"""
# Cached for performance. Invalidated on a layout request.
hint = self._size_hint
if hint.isValid():
return hint
# QTabWidget does not allow assigning a custom QStackedWidget,
# so the default sizeHint is computed, and the effects of the
# stack size hint are replaced by the current tab's size hint.
hint = super(QNotebook, self).sizeHint()
if self._size_hint_mode == QNotebook.Current:
stack = self.findChild(QStackedWidget)
if stack is not None:
curr = stack.currentWidget()
if curr is not None:
hint -= stack.sizeHint()
hint += curr.sizeHint()
self._size_hint = hint
return hint

def minimumSizeHint(self):
""" A reimplemented minimum size hint handler.
"""
# Cached for performance. Invalidated on a layout request.
hint = self._size_hint
if hint.isValid():
return hint
# QTabWidget does not allow assigning a custom QStackedWidget,
# so the default minimumSizeHint is computed, and the effects
# of the stack size hint are replaced by the current tab's
# minimum size hint.
hint = super(QNotebook, self).minimumSizeHint()
if self._size_hint_mode == QNotebook.Current:
stack = self.findChild(QStackedWidget)
if stack is not None:
curr = stack.currentWidget()
if curr is not None:
hint -= stack.minimumSizeHint()
hint += curr.minimumSizeHint()
self._size_hint = hint
return hint

def sizeHintMode(self):
""" Get the size hint mode of the notebook.
Returns
-------
result : QNotebook.SizeHintMode
The size hint mode enum value for the notebook.
"""
return self._size_hint_mode

def setSizeHintMode(self, mode):
""" Set the size hint mode of the notebook.
Parameters
----------
mode : QNotebook.SizeHintMode
The size hint mode for the notebook.
"""
assert isinstance(mode, QNotebook.SizeHintMode)
self._size_hint = QSize()
self._min_size_hint = QSize()
self._size_hint_mode = mode

def showPage(self, page):
""" Show a hidden QPage instance in the notebook.
Expand Down Expand Up @@ -261,6 +352,13 @@ def setTabsClosable(self, closable):
self._refreshTabBar()


#: A mapping Enaml -> Qt size hint modes.
SIZE_HINT_MODE = {
'union': QNotebook.Union,
'current': QNotebook.Current,
}


#: A guard flag for the tab change
CHANGE_GUARD = 0x01

Expand Down Expand Up @@ -300,6 +398,7 @@ def init_widget(self):
self.set_tab_position(d.tab_position)
self.set_tabs_closable(d.tabs_closable)
self.set_tabs_movable(d.tabs_movable)
self.set_size_hint_mode(d.size_hint_mode, update=False)
# the selected tab is synchronized during init_layout

def init_layout(self):
Expand Down Expand Up @@ -448,3 +547,11 @@ def set_selected_tab(self, name):
self.widget.setCurrentWidget(page)
finally:
self._guard &= ~CHANGE_GUARD

def set_size_hint_mode(self, mode, update=True):
""" Set the size hint mode for the widget.
"""
self.widget.setSizeHintMode(SIZE_HINT_MODE[mode])
if update:
self.size_hint_updated()
87 changes: 85 additions & 2 deletions enaml/qt/qt_stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#
# The full license is in the file COPYING.txt, distributed with this software.
#------------------------------------------------------------------------------
from atom.api import Int, Typed
from atom.api import Int, IntEnum, Typed

from enaml.widgets.stack import ProxyStack

Expand Down Expand Up @@ -63,6 +63,20 @@ class QStack(QStackedWidget):
""" A QStackedWidget subclass which adds support for transitions.
"""
class SizeHintMode(IntEnum):
""" An int enum defining the size hint modes of the stack.
"""
#: The size hint is the union of all stack items.
Union = 0

#: The size hint is the size hint of the current stack item.
Current = 1

#: Proxy the SizeHintMode values as if it were an anonymous enum.
Union = SizeHintMode.Union
Current = SizeHintMode.Current

#: A signal emitted when a LayoutRequest event is posted to the
#: stack widget. This will typically occur when the size hint of
#: the stack is no longer valid.
Expand All @@ -82,6 +96,7 @@ def __init__(self, *args, **kwargs):
self._painter = None
self._transition = None
self._transition_index = 0
self._size_hint_mode = QStack.Union

#--------------------------------------------------------------------------
# Private API
Expand Down Expand Up @@ -168,6 +183,57 @@ def event(self, event):
self.layoutRequested.emit()
return res

def sizeHint(self):
""" A reimplemented size hint handler.
This method will compute the size hint based on the size hint
of the current tab, instead of the default behavior which is
the maximum of all the size hints of the tabs.
"""
if self._size_hint_mode == QStack.Current:
curr = self.currentWidget()
if curr is not None:
return curr.sizeHint()
return super(QStack, self).sizeHint()

def minimumSizeHint(self):
""" A reimplemented minimum size hint handler.
This method will compute the size hint based on the size hint
of the current tab, instead of the default behavior which is
the maximum of all the minimum size hints of the tabs.
"""
if self._size_hint_mode == QStack.Current:
curr = self.currentWidget()
if curr is not None:
return curr.minimumSizeHint()
return super(QStack, self).minimumSizeHint()

def sizeHintMode(self):
""" Get the size hint mode of the stack.
Returns
-------
result : QStack.SizeHintMode
The size hint mode enum value for the stack.
"""
return self._size_hint_mode

def setSizeHintMode(self, mode):
""" Set the size hint mode of the stack.
Parameters
----------
mode : QStack.SizeHintMode
The size hint mode for the stack.
"""
assert isinstance(mode, QStack.SizeHintMode)
self._size_hint_mode = mode

def transition(self):
""" Get the transition installed on this widget.
Expand Down Expand Up @@ -219,6 +285,13 @@ def transitionTo(self, index):
self.setCurrentIndex(index)


#: A mapping Enaml -> Qt size hint modes.
SIZE_HINT_MODE = {
'union': QStack.Union,
'current': QStack.Current,
}


#: Cyclic notification guard
INDEX_FLAG = 0x1

Expand Down Expand Up @@ -247,7 +320,9 @@ def init_widget(self):
"""
super(QtStack, self).init_widget()
self.set_transition(self.declaration.transition)
d = self.declaration
self.set_transition(d.transition)
self.set_size_hint_mode(d.size_hint_mode, update=False)

def init_layout(self):
""" Initialize the layout of the underlying control.
Expand Down Expand Up @@ -337,3 +412,11 @@ def set_transition(self, transition):
self.widget.setTransition(make_transition(transition))
else:
self.widget.setTransition(None)

def set_size_hint_mode(self, mode, update=True):
""" Set the size hint mode for the widget.
"""
self.widget.setSizeHintMode(SIZE_HINT_MODE[mode])
if update:
self.size_hint_updated()
11 changes: 10 additions & 1 deletion enaml/widgets/notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def set_tabs_movable(self, movable):
def set_selected_tab(self, name):
raise NotImplementedError

def set_size_hint_mode(self, mode):
raise NotImplementedError


class Notebook(ConstraintsWidget):
""" A component which displays its children as tabbed pages.
Expand All @@ -60,6 +63,12 @@ class Notebook(ConstraintsWidget):
#: The object name for the selected tab in the notebook.
selected_tab = d_(Unicode())

#: The size hint mode for the stack. The default is 'union' and
#: means that the size hint of the notebook is the union of all
#: the tab size hints. 'current' means the size hint of the
#: notebook will be the size hint of the current tab.
size_hint_mode = d_(Enum('union', 'current'))

#: A notebook expands freely in height and width by default.
hug_width = set_default('ignore')
hug_height = set_default('ignore')
Expand All @@ -77,7 +86,7 @@ def pages(self):
# Observers
#--------------------------------------------------------------------------
@observe('tab_style', 'tab_position', 'tabs_closable', 'tabs_movable',
'selected_tab')
'selected_tab', 'size_hint_mode')
def _update_proxy(self, change):
""" Send the state change to the proxy.
Expand Down
11 changes: 10 additions & 1 deletion enaml/widgets/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def set_index(self, index):
def set_transition(self, transition):
raise NotImplementedError

def set_size_hint_mode(self, mode):
raise NotImplementedError


class Stack(ConstraintsWidget):
""" A component which displays its children as a stack of widgets,
Expand All @@ -62,6 +65,12 @@ class Stack(ConstraintsWidget):
#: The item transition to use when changing between stack items.
transition = d_(Typed(Transition))

#: The size hint mode for the stack. The default is 'union' and
#: means that the size hint of the stack is the union of all the
#: stack item size hints. 'current' means the size hint of the
#: stack will be the size hint of the current stack item.
size_hint_mode = d_(Enum('union', 'current'))

#: A Stack expands freely in height and width by default
hug_width = set_default('ignore')
hug_height = set_default('ignore')
Expand All @@ -78,7 +87,7 @@ def stack_items(self):
#--------------------------------------------------------------------------
# Observers
#--------------------------------------------------------------------------
@observe('index', 'transition')
@observe('index', 'transition', 'size_hint_mode')
def _update_proxy(self, change):
""" An observer which sends state change to the proxy.
Expand Down
6 changes: 6 additions & 0 deletions enaml/wx/wx_notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,3 +503,9 @@ def set_tabs_movable(self, movable):
else:
flags &= ~aui.AUI_NB_TAB_MOVE
widget.SetAGWWindowStyleFlag(flags)

def set_size_hint_mode(self, mode):
""" This is not supported on Wx.
"""
pass

0 comments on commit 330c7a3

Please sign in to comment.