Skip to content

Commit

Permalink
Merge pull request #28 from nmichaud/popup_anchor_mode
Browse files Browse the repository at this point in the history
Add screen/mouse anchoring mode to PopupView
  • Loading branch information
sccolbert committed Jun 20, 2013
2 parents 22e30cc + e90115a commit 74ddd47
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 14 deletions.
61 changes: 50 additions & 11 deletions enaml/qt/q_popup_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
# The full license is in the file COPYING.txt, distributed with this software.
#------------------------------------------------------------------------------
from PyQt4.QtCore import (
Qt, QPoint, QPointF, QMargins, QPropertyAnimation, QTimer, QEvent,
Qt, QPoint, QPointF, QSize, QMargins, QPropertyAnimation, QTimer, QEvent,
pyqtSignal
)
from PyQt4.QtGui import (
QApplication, QWidget, QLayout, QPainter, QPainterPath, QRegion, QPen
QApplication, QWidget, QLayout, QPainter, QPainterPath, QRegion, QPen,
QCursor
)

from atom.api import Atom, Typed, Float, Int
Expand Down Expand Up @@ -40,6 +41,12 @@ class QPopupView(QWidget):
#: The bottom edge of the popup view.
BottomEdge = 3

#: Anchor to parent (which can be None)
AnchorParent = 0

#: Anchor to mouse
AnchorCursor = 1

class ViewState(Atom):
""" A private class used to manage the state of a popup view.
Expand All @@ -52,6 +59,9 @@ class ViewState(Atom):
#: the top center of the view to the center of the parent.
parent_anchor = Typed(QPointF, factory=lambda: QPointF(0.5, 0.5))

#: Anchor to parent or cursor
anchor_mode = Int(0) # AnchorParent

#: The size of the arrow for the view.
arrow_size = Int(0)

Expand Down Expand Up @@ -175,6 +185,31 @@ def setAnchor(self, anchor):
state.anchor = anchor
self._updatePosition()

def anchorMode(self):
""" Get the anchor mode for the popup view
Returns
-------
result : int
An enum value describing the anchor mode of the popup.
"""
return self._state.anchor_mode

def setAnchorMode(self, mode):
""" Set the anchor mode for the popup view
Parameters
----------
mode : int
The anchor mode (can be AnchorParent or AnchorCursor)
"""
state = self._state
if mode != state.anchor_mode:
state.anchor_mode = mode
self._updatePosition()

def parentAnchor(self):
""" Get the parent anchor position for the popup view.
Expand Down Expand Up @@ -609,16 +644,20 @@ def _targetGlobalPos(self):
"""
state = self._state
parent = self.parent()
if parent is None:
# FIXME expose something other than the primary screen.
desktop = QApplication.desktop()
geo = desktop.availableGeometry()
origin = geo.topLeft()
size = geo.size()
if state.anchor_mode == QPopupView.AnchorCursor:
origin = QCursor.pos()
size = QSize()
else:
origin = parent.mapToGlobal(QPoint(0, 0))
size = parent.size()
parent = self.parent()
if parent is None:
# FIXME expose something other than the primary screen.
desktop = QApplication.desktop()
geo = desktop.availableGeometry()
origin = geo.topLeft()
size = geo.size()
else:
origin = parent.mapToGlobal(QPoint(0, 0))
size = parent.size()
anchor = state.parent_anchor
px = int(anchor.x() * size.width())
py = int(anchor.y() * size.height())
Expand Down
12 changes: 12 additions & 0 deletions enaml/qt/qt_popup_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
'tool_tip': Qt.ToolTip,
}

ANCHOR_MODE = {
'parent': QPopupView.AnchorParent,
'cursor': QPopupView.AnchorCursor,
}


class QtPopupView(QtWidget, ProxyPopupView):
""" A Qt implementation of an Enaml ProxyPopupView.
Expand Down Expand Up @@ -56,6 +61,7 @@ def init_widget(self):
super(QtPopupView, self).init_widget()
d = self.declaration
self.set_anchor(d.anchor)
self.set_anchor_mode(d.anchor_mode)
self.set_parent_anchor(d.parent_anchor)
self.set_arrow_size(d.arrow_size)
self.set_arrow_edge(d.arrow_edge)
Expand Down Expand Up @@ -113,6 +119,12 @@ def set_anchor(self, anchor):
"""
self.widget.setAnchor(QPointF(*anchor))

def set_anchor_mode(self, mode):
""" Set the anchor mode on the underlying widget.
"""
self.widget.setAnchorMode(ANCHOR_MODE[mode])

def set_parent_anchor(self, anchor):
""" Set the parent anchor location on the underlying widget.
Expand Down
13 changes: 10 additions & 3 deletions enaml/widgets/popup_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ class ProxyPopupView(ProxyWidget):
def set_anchor(self, anchor):
raise NotImplementedError

def set_anchor_mode(self, mode):
raise NotImplementedError

def set_parent_anchor(self, anchor):
raise NotImplementedError

Expand Down Expand Up @@ -109,6 +112,10 @@ class PopupView(Widget):
#: center of the parent widget.
anchor = d_(Coerced(PosF, (0.5, 0.0), coercer=coerce_posf))

#: If the anchor mode is cursor, ignore the parent and use the cursor
#: position for the popup
anchor_mode = d_(Enum('parent', 'cursor'))

#: The relative position on the parent to use as the anchor. This
#: anchor will be aligned with the view anchor to position the
#: popup view. It is expressed as a percentage of the parent size.
Expand Down Expand Up @@ -201,9 +208,9 @@ def close(self):
#--------------------------------------------------------------------------
# Observers
#--------------------------------------------------------------------------
@observe(('anchor', 'parent_anchor', 'arrow_size', 'arrow_edge',
'arrow_position', 'offset', 'timeout', 'fade_in_duration',
'fade_out_duration'))
@observe(('anchor', 'anchor_mode', 'parent_anchor', 'arrow_size',
'arrow_edge', 'arrow_position', 'offset', 'timeout',
'fade_in_duration', 'fade_out_duration'))
def _update_proxy(self, change):
""" Update the proxy when the PopupView data changes.
Expand Down
3 changes: 3 additions & 0 deletions examples/widgets/popup_view.enaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,6 @@ enamldef Main(Window): win:
PushButton:
text = 'Show Desktop Notification'
clicked :: NotificationPopup().show()
PushButton:
text = 'Show Mouse Notification'
clicked :: NotificationPopup(anchor_mode='cursor').show()

0 comments on commit 74ddd47

Please sign in to comment.