Created
February 13, 2018 08:09
-
-
Save jsbain/484d67d1f5f84d5c621d9e05683bb79d to your computer and use it in GitHub Desktop.
StatusBarOverlay.py
This file contains 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
# 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