class _View_Implementation(object): _View = ObjCSubclass('NSView', '_View') @_View.method(b'@' + PyObjectEncoding * 2) def initWithFrame_(self, frame, n): self = ObjCInstance(send_super(self, 'initWithFrame:', frame)) self.n = n # set up the angles loop step = 2 * PI / self.n self.loop = [i * step for i in range(self.n)] return self @_View.method('v@') def drawRect_(self, rect): # w, h = self.boundsSize().width, -.height b = rect or self.bounds() w = b.size.width * 0.5 h = b.size.height * 0.5 def _x(t, w): return (sin(t) + 1.) * w def _y(t, h): return (cos(t) + 1.) * h NSColor.whiteColor().set() NSRectFill(b) # not a class NSColor.blackColor().set() for f in self.loop: p1 = NSPoint_t(_x(f, w), _y(f, h)) for g in self.loop: p2 = NSPoint_t(_x(g, w), _y(g, h)) NSBezierPath.strokeLineFromPoint_toPoint_(p1, p2)
class _Delegate_Implementation(object): _Delegate = ObjCSubclass('NSObject', '_Delegate') # see pycocoa.runtime.parse_encoding for type encoding: # first is return value, then the method args, no need to # include @: for self and the Objective-C selector/cmd. @_Delegate.method(b'@' + PyObjectEncoding) def init(self, app): self = ObjCInstance(send_super(self, 'init')) # self = ObjCInstance(send_message('NSObject', 'alloc')) # print(self) # <ObjCInstance ...: _Delegate at ...> self.app = app return self @_Delegate.method('v@') def applicationDidFinishLaunching_(self, notification): '''Called automatically when the application has launched. ''' print('finished launching') @_Delegate.method('v@') def windowWillClose_(self, notification): '''Called automatically when the window is closed' ''' print('window will close') # Terminate the application self.app.terminate_(self) # or NSApp()...
class _Delegate_Implementation(object): _Delegate = ObjCSubclass('NSObject', '_Delegate') @_Delegate.method(b'@' + PyObjectEncoding) def init(self, app): self = ObjCInstance(send_super(self, 'init')) self.app = app return self @_Delegate.method(b'v@') def windowWillClose_(self, notification): self.app.terminate_(self)
class MySubclassImplementation(object): MySubclass = ObjCSubclass('NSObject', 'MySubclass') @MySubclass.method('v') def doSomething(self): if not hasattr(self, 'x'): self.x = 0 self.x += 1 print('doSomething', self.x) self.doSomething2() @MySubclass.method('v') def doSomething2(self): print('doSomething2', self.x)
class MySubclass_Implementation(object): # Create a Objective-C sub-class of NSObject MySubclass = ObjCSubclass('NSObject', 'MySubclass') # Through some magic, the self variable received by these # methods is an instance of the python ObjCInstance object. # It has an attribute objc_cmd set to the hidden _cmd # aka the selector argument. @MySubclass.method('@') # return type object, no args def init(self): self = ObjCInstance(send_super(self, 'init')) # self = ObjCInstance(send_message('NSObject', 'alloc')) print('inside init: self = %r' % (self,)) self.x = 1 return self # A normal Objective-C instance method. This gets added # to the Objective-C class. The type-encoding string says # that this method returns void and has no other arguments. @MySubclass.method('v') def doSomething(self): print('doSomething %s' % (self,)) print('x = %d' % (self.x,)) self.x += 1 @MySubclass.method('v@') # return void, 1 object def doSomethingElse(self, other): print('doSomethingElse %r %r' % (self, other)) other.doSomething() @MySubclass.method(b'v' + PyObjectEncoding) # return void, 1 Python object def takePyObject(self, pyobject): print('takePyObject %r %r' % (self, pyobject)) print('x = %d' % (self.x,)) @MySubclass.method('v') # return void, no args def dealloc(self): print('dealloc %r' % (self,)) send_super(self, 'dealloc') @MySubclass.method('vi') # return void, int arg def method(self, number): print('method %r %r' % (self, number))
class TheDelegate_Implementation(object): # NSObject): TheDelegate = ObjCSubclass('NSObject', 'TheDelegate') @TheDelegate.method('@') def init(self): # self = ObjCInstance(send_message('NSObject', 'alloc')) self = ObjCInstance(send_super(self, 'init')) # print(self) # <ObjCInstance 0x...: TheDelegate at ...> return self app = None badge = None # statusbar = None state = 'idle' @TheDelegate.method('v@') def applicationDidFinishLaunching_(self, notification): statusbar = NSStatusBar.systemStatusBar() statusitem = statusbar.statusItemWithLength_( NSVariableStatusItemLength) # statusitem.setHighlightMode_(1) # statusitem.setToolTip_(NSStr('Example')) # statusitem.setTitle_(NSStr('Example')) menu = NSMenu.alloc().init() menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( NSStr('Quit'), get_selector('terminate:'), NSStr('')) menu.addItem_(menuitem) statusitem.setMenu_(menu) @TheDelegate.method(b'v' + PyObjectEncoding) def writer(self, s): self.badge.setBadgeLabel_(NSStr(str(s))) @TheDelegate.method(b'v@') def windowWillClose_(self, notification): if self.app: self.app.terminate_(self)
class _Delegate_Implementation(object): # Cobbled together from the pycocoa.ObjCSubClass.__doc__, # pycocoa.runtime._DeallocObserver and PyObjC examples: # <https://TaoOfMac.com/space/blog/2007/04/22/1745> and # <https://StackOverflow.com/questions/24024723/swift-using # -nsstatusbar-statusitemwithlength-and-nsvariablestatusitemlength> _Delegate = ObjCSubclass('NSObject', '_Delegate') # The _Delegate.method(signature) decorator specfies the # signature of a Python method in Objective-C type encoding # and makes the Python method callable from Objective-C. # This is rather ugly, especially since the decorator is # also required for (private) methods called only from # Python. # See pycocoa.octypes.split_emcoding2 for type encoding: # first is return value, then the method args, no need to # include @: for self and the Objective-C selector/cmd. @_Delegate.method(b'@' + PyObjectEncoding * 4) def init(self, app, player, title, video): self = ObjCInstance(send_super(self, 'init')) # self = ObjCInstance(send_message('NSObject', 'alloc')) self.app = app self.NSitem = None # Play/Pause toggle self.player = player self.ratio = 2 self.title = title # app name, top-level menu title self.video = video # window banner self.window = None nsBundleRename(NSStr(title)) # top-level menu title return self @_Delegate.method('v@') # void, ObjC def applicationDidFinishLaunching_(self, notification): # the player needs an NSView object self.window, view = _Window2(title=self.video or self.title) # set the window's delegate to the app's to # make method .windowWillClose_ work, see # <https://Gist.GitHub.com/kaloprominat/6105220> self.window.setDelegate_(self) # pass viewable to VLC player self.player.set_nsobject(view) menu = NSMenu.alloc().init() # create main menu menu.addItem_( _MenuItem('Full ' + 'Screen', 'enterFullScreenMode:', 'f', ctrl=True)) # Ctrl-Cmd-F, Esc to exit menu.addItem_(_MenuItem('Info', 'info:', 'i')) menu.addItem_(_MenuItemSeparator()) self.NSitem = _MenuItem('Pause', 'toggle:', 'p', ctrl=True) # Ctrl-Cmd-P menu.addItem_(self.NSitem) menu.addItem_(_MenuItem('Rewind', 'rewind:', 'r', ctrl=True)) # Ctrl-Cmd-R menu.addItem_(_MenuItemSeparator()) menu.addItem_(_MenuItem('Hide ' + self.title, 'hide:', 'h')) # Cmd-H, implied menu.addItem_( _MenuItem('Hide Others', 'hideOtherApplications:', 'h', alt=True)) # Alt-Cmd-H menu.addItem_(_MenuItem('Show All', 'unhideAllApplications:')) # no key menu.addItem_(_MenuItemSeparator()) menu.addItem_(_MenuItem('Quit ' + self.title, 'terminate:', 'q')) # Cmd-Q subMenu = NSMenuItem.alloc().init() subMenu.setSubmenu_(menu) menuBar = NSMenu.alloc().init() menuBar.addItem_(subMenu) self.app.setMainMenu_(menuBar) self.player.play() # adjust the contents' aspect ratio self.windowDidResize_(None) @_Delegate.method('v@') def info_(self, notification): try: p = self.player if p.is_playing(): p.pause() m = p.get_media() v = sys.modules[p.__class__.__module__] # import vlc b = v.bytes_to_str printf(__version__, nl=1) # print Python, vlc, libVLC, media info printf('PyCocoa %s', __PyCocoa__) printf('Python %s %s', sys.version.split()[0], architecture()[0]) printf('macOS %s %s', mac_ver()[0], machine(), nt=1) printf('vlc.py %s (%#x)', v.__version__, v.hex_version()) printf('built: %s', v.build_date) printf('libVLC %s (%#x)', b(v.libvlc_get_version()), v.libvlc_hex_version()) printf('libVLC %s', b(v.libvlc_get_compiler()), nt=1) printf('media: %s', b(m.get_mrl())) printf('state: %s', p.get_state()) printf('track/count: %s/%s', p.video_get_track(), p.video_get_track_count()) printf('time/duration: %s/%s ms', p.get_time(), m.get_duration()) printf('position/length: %.2f%%/%s ms', p.get_position() * 100.0, p.get_length()) f = p.get_fps() printf('fps: %.3f (%.3f ms)', f, mspf(f)) printf('rate: %s', p.get_rate()) w, h = p.video_get_size(0) printf('video size: %sx%s', w, h) r = gcd(w, h) or '' if r and w and h: r = ' (%s:%s)' % (w // r, h // r) printf('aspect ratio: %s%s', p.video_get_aspect_ratio(), r) printf('scale: %.3f', p.video_get_scale()) o = p.get_nsobject() # for macOS only printf('nsobject: %r (%#x)', o, o, nt=1) except Exception as x: printf('%r', x, nl=1, nt=1) @_Delegate.method('v@') def rewind_(self, notification): self.player.set_position(0.0) # can't re-play once at the end # self.player.play() @_Delegate.method('v@') def toggle_(self, notification): # toggle between Pause and Play if self.player.is_playing(): # note, .pause() pauses and un-pauses the video, # .stop() stops the video and blanks the window self.player.pause() t = 'Play' else: self.player.play() t = 'Pause' self.NSitem.setTitle_(NSStr(t)) @_Delegate.method('v@') def windowDidResize_(self, notification): if self.ratio and self.player and self.window: # get and maintain the aspect ratio # (the first player.video_get_size() # call returns (0, 0), subsequent # calls return (w, h) correctly) r = aspect_ratio(*self.player.video_get_size(0)) if r: self.window.setContentAspectRatio_(NSSize_t(*r)) self.ratio -= 1 @_Delegate.method('v@') def windowWillClose_(self, notification): self.app.terminate_(self) # or NSApp()...
class AppDelegate(object): # Cobbled together from the pycocoa.ObjCSubClass.__doc__, # pycocoa.runtime._DeallocObserver and PyObjC examples: # <http://taoofmac.com/space/blog/2007/04/22/1745> and # <http://stackoverflow.com/questions/24024723/swift-using # -nsstatusbar-statusitemwithlength-and-nsvariablestatusitemlength> _Delegate = ObjCSubclass('NSObject', '_Delegate') # the _Delegate.method(signature) decorator specfies the # signature of a Python method in Objective-C type encoding # to make the Python method callable from Objective-C. # This is rather ugly, especially since the decorator is # also required for (private) methods called only from # Python, like method .badgelabel, ._rate and ._zoom below. # See pycocoa.runtime.split_encoding for type encoding: # first is return value, then the method args, no need to # include @: for self and the Objective-C selector/cmd. @_Delegate.method(b'@' + PyObjectEncoding * 3) def init(self, title, app, url): self = ObjCInstance(send_super_init(self)) self.title = title self.app = app self.player = vlc.Instance('--rtsp-tcp').media_player_new(uri=url) self.ratio = 2 self.scale = 1 return self @_Delegate.method('v@') def applicationDidFinishLaunching_(self, notification): self.window, view = new_window(title=self.title) self.window.setDelegate_(self) self.player.set_nsobject(view) # Create the main menu. menu = NSMenu.alloc().init() menu.addItem_( new_menu_item( 'Full Screen', 'enterFullScreenMode:', 'f', ctrl=True ) ) menu.addItem_(new_menu_seperator()) menu.addItem_(new_menu_item('Play', 'play:', 'p')) menu.addItem_(new_menu_item('Pause', 'pause:', 's')) menu.addItem_(new_menu_seperator()) menu.addItem_(new_menu_item('Faster', 'faster:', '>', shift=True)) menu.addItem_(new_menu_item('Slower', 'slower:', '<', shift=True)) menu.addItem_(new_menu_item('Zoom In', 'zoomIn:', '+')) menu.addItem_(new_menu_item('Zoom Out', 'zoomOut:', '-')) menu.addItem_(new_menu_seperator()) menu.addItem_(new_menu_item('Close Window', 'windowWillClose:', 'w')) menu.addItem_(new_menu_seperator()) menu.addItem_(new_menu_item('Hide Window', 'hide:', 'h')) menu.addItem_( new_menu_item( 'Hide Others', 'hideOtherApplications:', 'h', alt=True ) ) menu.addItem_(new_menu_item('Show All', 'unhideAllApplications:')) menu.addItem_(new_menu_seperator()) menu.addItem_(new_menu_item('Quit ' + self.title, 'terminate:', 'q')) subMenu = NSMenuItem.alloc().init() subMenu.setSubmenu_(menu) menuBar = NSMenu.alloc().init() menuBar.addItem_(subMenu) self.app.setMainMenu_(menuBar) self.play_(None) @_Delegate.method('v@') def pause_(self, notification): # note, .pause() pauses and un-pauses the video, # .stop() stops the video and blanks the window if self.player.is_playing(): self.player.pause() @_Delegate.method('v@') def play_(self, notification): self.player.play() @_Delegate.method('v@') def windowDidResize_(self, notification): if self.window and self.ratio: # get and maintain the aspect ratio # (the first player.video_get_size() # call returns (0, 0), subsequent # calls return (w, h) correctly) w, h = self.player.video_get_size(0) r = gcd(w, h) if r and w and h: r = NSSize_t(w // r, h // r) self.window.setContentAspectRatio_(r) self.ratio -= 1 @_Delegate.method('v@') def windowWillClose_(self, notification): self.app.terminate_(self) @_Delegate.method('v@') def faster_(self, notification): self._rate(2.0) @_Delegate.method('v@') def slower_(self, notification): self._rate(0.5) @_Delegate.method(b'v' + PyObjectEncoding) def _rate(self, factor): # called from ObjC method r = self.player.get_rate() * factor if 0.2 < r < 10.0: self.player.set_rate(r) @_Delegate.method('v@') def zoomIn_(self, notification): self._zoom(1.25) @_Delegate.method('v@') def zoomOut_(self, notification): self._zoom(0.80) @_Delegate.method(b'v' + PyObjectEncoding) def _zoom(self, factor): # called from ObjC method self.scale *= factor self.player.video_set_scale(self.scale)
class _Delegate_Implementation(object): # Cobbled together from the pycocoa.ObjCSubClass.__doc__, # pycocoa.runtime._DeallocObserver and PyObjC examples: # <http://TaoOfMac.com/space/blog/2007/04/22/1745> and # <http://StackOverflow.com/questions/24024723/swift-using # -nsstatusbar-statusitemwithlength-and-nsvariablestatusitemlength> _Delegate = ObjCSubclass('NSObject', '_Delegate') # the _Delegate.method(signature) decorator specfies the # signature of a Python method in Objective-C type encoding # to make the Python method callable from Objective-C. # This is rather ugly, especially since the decorator is # also required for (private) methods called only from # Python, like method .badgelabel, ._rate and ._zoom below. # See pycocoa.runtime.split_encoding for type encoding: # first is return value, then the method args, no need to # include @: for self and the Objective-C selector/cmd. @_Delegate.method(b'@' + PyObjectEncoding * 3) def init(self, app, title, video): self = ObjCInstance(send_super(self, 'init')) # self = ObjCInstance(send_message('NSObject', 'alloc')) self.app = app self.player = vlc.MediaPlayer(video) self.ratio = 2 self.scale = 1 self.title = title self.video = video # file name in window banner self.window = None return self @_Delegate.method('v@') def applicationDidFinishLaunching_(self, notification): # the player needs an NSView object self.window, view = _Window2(title=self.video or self.title) # set the window's delegate to the app's to # make method .windowWillClose_ work, see # <http://Gist.GitHub.com/kaloprominat/6105220> self.window.setDelegate_(self) # Create the main menu. menu = NSMenu.alloc().init() menu.addItem_(_MenuItem('Full ' + 'Screen', 'enterFullScreenMode:', 'f', ctrl=True)) # Ctrl-Cmd-F, Esc to exit if self.player: # setup player view and menu self.player.set_nsobject(view) menu.addItem_(_MenuItemSeparator()) menu.addItem_(_MenuItem('Play', 'play:', 'p')) menu.addItem_(_MenuItem('Pause', 'pause:', 's')) menu.addItem_(_MenuItem('Rewind', 'rewind:', 'r')) menu.addItem_(_MenuItemSeparator()) menu.addItem_(_MenuItem('Faster', 'faster:', '>', shift=True)) menu.addItem_(_MenuItem('Slower', 'slower:', '<', shift=True)) menu.addItem_(_MenuItem('Zoom In', 'zoomIn:', '+')) menu.addItem_(_MenuItem('Zoom Out', 'zoomOut:', '-')) menu.addItem_(_MenuItemSeparator()) menu.addItem_(_MenuItem('Info', 'info:', 'i')) menu.addItem_(_MenuItem('Close Windows', 'windowWillClose:', 'w')) menu.addItem_(_MenuItemSeparator()) menu.addItem_(_MenuItem('Hide ' + self.title, 'hide:', 'h')) # Cmd-H, implied menu.addItem_(_MenuItem('Hide Others', 'hideOtherApplications:', 'h', alt=True)) # Alt-Cmd-H menu.addItem_(_MenuItem('Show All', 'unhideAllApplications:')) # no key menu.addItem_(_MenuItemSeparator()) menu.addItem_(_MenuItem('Quit ' + self.title, 'terminate:', 'q')) # Cmd-Q subMenu = NSMenuItem.alloc().init() subMenu.setSubmenu_(menu) menuBar = NSMenu.alloc().init() menuBar.addItem_(subMenu) self.app.setMainMenu_(menuBar) self.play_(None) # adjust the contents' aspect ratio self.windowDidResize_(None) @_Delegate.method('v@') def info_(self, notification): try: self.pause_(notification) p = self.player m = p.get_media() # print Python, vlc, libVLC, media info _printf('PyCocoa %s (%s)', __PyCocoa__, __version__, nl=1) _printf('python %s', ' '.join(_Python)) _printf('macOS %s', ' '.join(_macOS)) _printf('vlc.py %s (%#x)', vlc.__version__, vlc.hex_version()) _printf('built: %s', vlc.build_date) _printf('libVLC %s (%#x)', _b2str(vlc.libvlc_get_version()), vlc.libvlc_hex_version()) _printf('libVLC %s', _b2str(vlc.libvlc_get_compiler()), nt=1) _printf('media: %s', _b2str(m.get_mrl())) _printf('state: %s', p.get_state()) _printf('track/count: %s/%s', p.video_get_track(), p.video_get_track_count()) _printf('time/duration: %s/%s ms', p.get_time(), m.get_duration()) _printf('position/length: %.2f%%/%s ms', p.get_position() * 100.0, p.get_length()) f = p.get_fps() _printf('fps: %.3f (%.3f ms)', f, _mspf(f)) _printf('rate: %s', p.get_rate()) w, h = p.video_get_size(0) r = gcd(w, h) or '' if r and w and h: r = ' (%s:%s)' % (w // r, h // r) _printf('video size: %sx%s%s', w, h, r) # num=0 _printf('aspect ratio: %s', p.video_get_aspect_ratio()) _printf('scale: %.3f (%.3f)', p.video_get_scale(), self.scale) _printf('window: %r', p.get_hwnd(), nt=1) except Exception as x: _printf('%r', x, nl=1, nt=1) @_Delegate.method('v@') def pause_(self, notification): # note, .pause() pauses and un-pauses the video, # .stop() stops the video and blanks the window if self.player.is_playing(): self.player.pause() @_Delegate.method('v@') def play_(self, notification): self.player.play() @_Delegate.method('v@') def rewind_(self, notification): self.player.set_position(0.0) # can't re-play once at the end # self.player.play() @_Delegate.method('v@') def windowDidResize_(self, notification): if self.window and self.ratio: # get and maintain the aspect ratio # (the first player.video_get_size() # call returns (0, 0), subsequent # calls return (w, h) correctly) w, h = self.player.video_get_size(0) r = gcd(w, h) if r and w and h: r = NSSize_t(w // r , h // r) self.window.setContentAspectRatio_(r) self.ratio -= 1 @_Delegate.method('v@') def windowWillClose_(self, notification): self.app.terminate_(self) # or NSApp()... @_Delegate.method('v@') def faster_(self, notification): self._rate(2.0) @_Delegate.method('v@') def slower_(self, notification): self._rate(0.5) @_Delegate.method(b'v' + PyObjectEncoding) def _rate(self, factor): # called from ObjC method r = self.player.get_rate() * factor if 0.2 < r < 10.0: self.player.set_rate(r) @_Delegate.method('v@') def zoomIn_(self, notification): self._zoom(1.25) @_Delegate.method('v@') def zoomOut_(self, notification): self._zoom(0.80) @_Delegate.method(b'v' + PyObjectEncoding) def _zoom(self, factor): # called from ObjC method self.scale *= factor self.player.video_set_scale(self.scale)