Last active
February 17, 2016 07:27
-
-
Save typemytype/6429212 to your computer and use it in GitHub Desktop.
A vanilla Popover proposal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from AppKit import * | |
from vanilla.vanillaBase import _setAttr, _delAttr, VanillaBaseObject | |
_edgeMap = { | |
"left" : NSMinXEdge, | |
"right" : NSMaxXEdge, | |
"top" : NSMinYEdge, | |
"bottom" : NSMaxYEdge | |
} | |
_popoverBehaviorMap = { | |
"normal" : 0, | |
"asMenu" : 1, | |
"semiAsMenu" : 2 | |
} | |
class PopoverContentView(NSView): | |
def _getContentView(self): | |
return self | |
class Popover(NSObject): | |
nsContentViewClass = PopoverContentView | |
def __new__(cls, *args, **kwargs): | |
return cls.alloc().init() | |
def __init__(self, posSize, parentView, edge, relativeRect=None, HUD=False, behavior="normal"): | |
# transform the parentView to a NSView | |
if isinstance(parentView, VanillaBaseObject): | |
parentView = parentView._getContentView() | |
self._parentView = parentView | |
# get the edge from the edge map | |
self._edge = _edgeMap[edge] | |
# if no relative Rect is given use a NSZeroRect | |
# so the bounds of the relative view is used | |
if relativeRect is None: | |
relativeRect = NSZeroRect | |
self._relativeRect = relativeRect | |
self._bindings = {} | |
w, h = posSize | |
# setup the content view | |
self._contentView = self.nsContentViewClass.alloc().initWithFrame_(NSMakeRect(0, 0, w, h)) | |
# create a view controller | |
self._contentViewController = NSViewController.alloc().init() | |
# add the view | |
self._contentViewController.setView_(self._contentView) | |
# create a NSPopover | |
self._nsObject = NSPopover.alloc().init() | |
# set the delegate | |
self._nsObject.setDelegate_(self) | |
# set HUD if necessary (black UI) | |
if HUD: | |
self._nsObject.setAppearance_(1) | |
# set the behavior of the popover | |
self._nsObject.setBehavior_(_popoverBehaviorMap[behavior]) | |
# set the content view controller | |
self._nsObject.setContentViewController_(self._contentViewController) | |
def __setattr__(self, attr, value): | |
if isinstance(value, VanillaBaseObject): | |
_setAttr(self.nsContentViewClass, self._contentView, attr, value) | |
else: | |
super(Popover, self).__setattr__(attr, value) | |
def __delattr__(self, attr): | |
if hasattr(self._contentView, attr): | |
_delAttr(self.nsContentViewClass, self._contentView, attr) | |
else: | |
super(Popover, self).__delattr__(attr) | |
def open(self, view=None, relativeRect=None, edge=None): | |
if view is not None: | |
# transform the parentView to a NSView | |
if isinstance(view, VanillaBaseObject): | |
view = view._getContentView() | |
self._parentView = view | |
if relativeRect is not None: | |
self._relativeRect = relativeRect | |
if edge is not None: | |
self._edge = edge | |
# open the pop over | |
self._nsObject.showRelativeToRect_ofView_preferredEdge_(self._relativeRect, self._parentView, self._edge) | |
def close(self): | |
# close the pop over | |
self._nsObject.close() | |
def resize(self, width, height, animate=True): | |
self._nsObject.setAnimates_(animate) | |
self._nsObject.setContentSize_((width, height)) | |
## notifications | |
def bind(self, event, callback): | |
# same as in a Window object | |
if event not in self._bindings: | |
self._bindings[event] = [] | |
self._bindings[event].append(callback) | |
def unbind(self, event, callback): | |
self._bindings[event].remove(callback) | |
def _alertBindings(self, event): | |
if hasattr(self, "_bindings"): | |
if event in self._bindings: | |
for callback in self._bindings[event]: | |
return callback(self) | |
def popoverWillShow_(self, notification): | |
self._alertBindings("will show") | |
def popoverDidShow_(self, notification): | |
self._alertBindings("did show") | |
def popoverShouldClose_(self, notification): | |
shouldClose = self._alertBindings("should close") | |
if shouldClose is None: | |
shouldClose = True | |
return shouldClose | |
def popoverWillClose_(self, notification): | |
self._alertBindings("will close") | |
if __name__ == "__main__": | |
from vanilla import * | |
from defconAppKit.windows.baseWindow import BaseWindowController | |
from random import randint | |
class TestingPopOver(BaseWindowController): | |
def __init__(self): | |
self.w = Window((400, 400), "PopOver") | |
self.w.button = Button((10, 10, 150, 22), "Pop Me Up, Scotty", callback=self.buttonCallback) | |
self.popover = Popover((200, 200), self.w.button, "top", behavior="semiAsMenu") | |
self.popover.text = TextBox((10, 10, 100, 22), "Hi") | |
self.popover.resize = Button((10, -70, 100, 22), "reisze", callback=self.resizeCallback) | |
self.popover.closeButton = Button((10, -30, 100, 22), "Close", callback=self.closePopoverCallback) | |
self.w.open() | |
def buttonCallback(self, sender): | |
self.popover.open() | |
def resizeCallback(self, sender): | |
self.popover.resize(200, randint(200, 400)) | |
def closePopoverCallback(self, sender): | |
self.popover.close() | |
from vanilla.test.testTools import executeVanillaTest | |
executeVanillaTest(TestingPopOver) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment