Skip to content

Instantly share code, notes, and snippets.

@jsbain
Created February 13, 2018 08:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsbain/484d67d1f5f84d5c621d9e05683bb79d to your computer and use it in GitHub Desktop.
Save jsbain/484d67d1f5f84d5c621d9e05683bb79d to your computer and use it in GitHub Desktop.
StatusBarOverlay.py
# coding: utf-8
''' Statusbarmenu
A menu that lives in the status bar
A set of tools to add or delete custom buttons from the toolbar. This may not be super robust, but seems to work ok. Button objects and actions are saved so they survive global clearing, but thid has not been tested extensively. If a function relies on imports that occured outside of the function, these might dissappear -- user must make sure those modules are added to a module that is kept by pythonista, such as anything in site-packages, or name starting with __ '''
from objc_util import *
import ui,console,editor
import weakref
from functools import partial
MARGIN=10
HEIGHT=32
CORNERWIDTH=80
try:
__s.teardown()
del __s
except NameError:
pass
class WrappingToolbar(ui.View):
def __init__(self, btn):
self.btn=btn
def layout(self):
# called when containing view changes size
buttonwidth=sum([(sv.width+MARGIN) for sv in self.subviews])
parent_width=self.objc_instance.superview().frame().size.width
self.height=HEIGHT
if buttonwidth > parent_width-2*MARGIN-self.btn.width:
self.width=parent_width-self.btn.width
else:
self.width=buttonwidth
x=MARGIN
y=0
for v in self.subviews:
v.x = x
v.y=y
x += v.width+MARGIN
if x > self.width:
x=MARGIN
y+=HEIGHT
self.height += HEIGHT+MARGIN/2
def add_view(self):
pass
class StatusBarOverlay(object):
def __init__(self,height=HEIGHT):
self.height=height
app=UIApplication.sharedApplication()
self.bar=app.statusBar()
b=self.bar.bounds()
btn=ui.Button(frame=(0,0,CORNERWIDTH,20))
self.overlay=WrappingToolbar(btn)
self.overlay.flex='w'
self.overlay.y=-self.overlay.height
#self.overlay.border_color='#ff0000'
self.overlay.border_width=1
self.overlay.corner_radius=5
self.bar.addSubview_(self.overlay)
btn.height=20
btn.width=CORNERWIDTH
btn.flex='l'
btn.alpha=.6
btn.x=b.size.width-CORNERWIDTH
btn.action=self.toggleBar
with ui.ImageContext(CORNERWIDTH,20) as ctx:
p=ui.Path()
p.move_to(0,0)
p.move_to(CORNERWIDTH-30,0)
p.line_to(CORNERWIDTH,20)
p.line_to(CORNERWIDTH,0)
#p.line_to(CORNERWIDTH,20)
#p.line_to(0,20)
p.line_width=4
p.close()
ui.set_color((1,0,0,1))
p.stroke()
p.fill()
btn.image=ctx.get_image()
self.btn=btn
self.overlay.bg_color='white'
self.expanded=False
self.bar.addSubview_(btn)
self.overlay.x=self.btn.x+CORNERWIDTH
self.overlay.bring_to_front
self.btn.bring_to_front
def toggleBar(self,sender):
''' display self.overlay'''
if self.expanded:
#hide
def ani():
self.overlay.x=self.btn.x-self.overlay.width
#self.overlay.alpha=0
self.overlay.y=-self.overlay.height
else: #show
def ani():
self.overlay.x=self.btn.x-self.overlay.width
#self.overlay.alpha=1
self.overlay.y=0
self.expanded=not (self.expanded)
ui.animate(ani,.25)
self.overlay.layout()
def add_action(self,action,title=None,image=None):
'''adds a button to the overlay, at next position'''
b=ui.Button(title=title,image=image,action=action)
b.size_to_fit()
self.overlay.add_subview(b)
self.overlay.layout()
self.overlay.x=self.btn.x-self.overlay.width-MARGIN
@on_main_thread
def teardown(self):
'''cleanup...'''
self.overlay.objc_instance.removeFromSuperview()
self.btn.objc_instance.removeFromSuperview()
def __del__(self):
self.teardown()
if __name__=='__main__':
#for debug only:
app=UIApplication.sharedApplication()
bar=app.statusBar()
#dummy action
def a(sender):
'''generic action, to print x position of button'''
print(sender.x)
__s=StatusBarOverlay() #dunder retains in globals...
__s.add_action(a,'Title') #title only
__s.add_action(a,image=ui.Image.named('iow:archive_32')) #image only
__s.add_action(a,'Blah')
__s.add_action(a,'Find',ui.Image.named('iow:search_32')) #title and image
__s.add_action(a,'Copy',ui.Image.named('iow:clipboard_32')) #title and image
__s.add_action(a,'CopyCopysisjsn',ui.Image.named('iow:clipboard_32')) #title and image
__s.add_action(a,'Copy',ui.Image.named('iow:clipboard_32')) #title and image
with ui.ImageContext(32,32) as ctx:
ui.Image.named('iob:chatbox_32').draw(0,0,32,32)
ui.set_blend_mode(ui.BLEND_CLEAR)
ui.draw_string('hello',[5,5,21,21],font=('<system>',9),color='white')
img=ctx.get_image()
__s.add_action(a,image=img) #custom icon
with ui.ImageContext(32,32) as ctx:
ui.Path.oval(3,3,28,23).stroke()
ui.draw_string('Sage',[5,7,21,21],font=('<system>',7))
img=ctx.get_image()
__s.add_action(a,image=img) #custom icon
__s.add_action(a,'VeryLongTitle')
__s.add_action(a,'AnotherVeryLongTitle')
__s.add_action(a,'Copy',ui.Image.named('iow:clipboard_32')) #title and image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment