Skip to content

Instantly share code, notes, and snippets.

@JMV38
Created August 18, 2019 11:22
Embed
What would you like to do?
appli.py
import ui, photos, console, json, copy, math, io, os, dialogs, webbrowser
from PIL import Image
from numpy import clip
version = 9
# constants
TOP = 'TOP'
PHOTOS1 = 'PHOTOS'
PHOTOS2 = 'TEMP'
EDITOR = 'EDITOR'
PAGES = 'PAGES'
tw = None
def getAssets():
suffix1 = '_pages_and_photos'
suffix2 = '_pages'
lst = photos.get_albums()
# a dictionnary to acces albums via their title
allAlbums = dict()
for album in lst:
allAlbums.update({album.title:album})
# the usable albums are the ones i have not created
inputAlbums = dict()
for title in allAlbums.keys():
if title[-len(suffix1):] != suffix1 and title[-len(suffix2):] != suffix2:
inputAlbums.update({title:allAlbums[title]})
# choose the album uo use
inputTitle = dialogs.list_dialog('Select an album', list(inputAlbums.keys()))
inputAlbum = allAlbums[inputTitle]
# get the output albums (create it if it does not exist)
outputTitle1 = inputTitle + suffix1
try: outputAlbum1 = allAlbums[outputTitle1]
except: outputAlbum1 = photos.create_album(outputTitle1)
outputTitle2 = inputTitle + suffix2
try: outputAlbum2 = allAlbums[outputTitle2]
except: outputAlbum2 = photos.create_album(outputTitle2)
# get assets
inputAssets = list(inputAlbum.assets)
outputAssets = list(outputAlbum1.assets)
pageAssets = list(outputAlbum2.assets)
# remove from input the assets already used
for asset in outputAssets:
if asset in inputAssets: inputAssets.remove(asset)
return inputAssets, pageAssets, outputAlbum1, outputAlbum2
def save(page, outputAlbum1, outputAlbum2, thumbs):
if len(thumbs) == 0:
console.hud_alert('nothing to save', 'error')
return
# save page image in pythonista
path = 'temp.jpg'
with ui.ImageContext(page.width, page.height) as ctx:
page.draw_snapshot()
ui_image = ctx.get_image()
pil = Image.open(io.BytesIO(ui_image.to_png()))
crop_pil = pil
crop_pil.save(path , quality=95)
# save page image in albums
asset = photos.create_image_asset(path)
os.remove(path)
outputAlbum1.add_assets([asset])
outputAlbum2.add_assets([asset])
photos2.add(Thumb(bg,asset,100))
photos2.layout()
# save used photos in albums
for thumb in thumbs:
asset = thumb.asset
if asset in outputAlbum1.assets : outputAlbum1.remove_assets([asset])
outputAlbum1.add_assets([asset])
thumb.saved = True
console.hud_alert('saved')
page.saved = True
class Splitter(ui.View):
# an invisible touch sensor to adjust the edge of containers
def __init__(self, name, parentView, y, ymin, ymax, **kvargs):
super(Splitter,self).__init__(**kvargs)
self.name = name
self.moving = EventHook(y='new center line y position') # the event to manage movement
w,h = ui.get_screen_size()
self.frame = (w-100, 0, 80, 30)
self.yc, self.ymin, self.ymax = y, ymin, ymax # the center of the view is used to keep it simple
self.setPosition(y)
self.background_color = (0.5, 0.5, 0.5, 0.4) # change alpha to 0.2 to see sensor
self.border_width = 1
self.border_color = 0
parentView.add_subview(self)
def setPosition(self, y):
self.yc = clip(y, self.ymin, self.ymax) # make sure the center position is within its bounds
self.y = self.yc - self.height/2 # now move the splitter
def moveCenter(self, dy):
self.setPosition(self.yc + dy)
def touch_moved(self, touch):
dx,dy = touch.location - touch.prev_location
yc = self.yc + dy
yc = clip(yc, self.ymin, self.ymax)
dy = yc - self.yc
self.moveCenter(dy) # move the splitter
self.moving(dy) # tell the world
finger.moveToTouch(touch, self)
def touch_began(self, touch): finger.moveToTouch(touch, self)
def touch_ended(self, touch): finger.moveToTouch(touch, self)
def infoPrint(txt):
if tw: print(txt)
class Container(ui.View):
# a horizontal container
def __init__(self, *args, **kvargs):
self.ready = False # ready is used for touch and layout
self.setup(*args, **kvargs) # call .setup(...) in the suclasses instead of .__init__
bg.drop += self.receive
self.ready = True
self.layout()
def setup(self, name, parentView=None, y=None, h=None, **kvargs):
super(Container,self).__init__(**kvargs)
self.background_color, self.border_width, self.border_color = (0.3,0.3,0.3,0.5), 1, 0
self.name = name
w0,h0= ui.get_screen_size()
self.frame = (0, y or 0, w0, h or h0)
if parentView: parentView.add_subview(self)
self.ThumbContainer = self
self.ThumbClass = Thumb
self.thumbs = []
self.grid = False
def moveLowerEdge(self, dy):
self.height += dy
def moveUpperEdge(self, dy):
self.height -= dy
self.y += dy
def add(self, thumb, pos=-1):
#self.info(thumb, 'add')
self.xyToLocal(thumb)
if self.ThumbClass and not type(thumb) == self.ThumbClass:
newThumb = self.ThumbClass(self, thumb.asset, thumb.height, name=thumb.name)
newThumb.frame = thumb.frame
thumb.close()
thumb = newThumb
else:
thumb.top = self
self.thumbs.insert(pos, thumb)
self.ThumbContainer.add_subview(thumb)
thumb.bring_to_front()
return thumb
#self.info(thumb, 'added')
def info(self, thumb, txt):
if tw: print('{} {} {}: at x,y = {} , {}'.format( self.name, txt, thumb.name, thumb.x, thumb.y))
def printSuperviewName(self,thumb):
name = None
ct = thumb
while not isinstance(ct, Container):
try: ct = ct.superview
except: break
try: name = ct.name
except: pass
infoPrint('{} is in view {}'.format(thumb.name, name))
def getThumbLocalOffset(self):
ox = self.x - bg.x
oy = self.y - bg.y
return ox,oy
def xyToLocal(self, thumb):
ox,oy = self.getThumbLocalOffset()
thumb.x -= ox
thumb.y -= oy
def xyToGlobal(self, thumb):
ox,oy = self.getThumbLocalOffset()
thumb.x += ox
thumb.y += oy
def remove(self, thumb):
#self.info(thumb,'remove')
if thumb in self.thumbs: self.thumbs.remove(thumb)
# note: no need to remove from subviews: this is done by add_view(thumb)
self.removeAnimation(thumb)
def removeAnimation(self,thumb):
pass
def delete(self, thumb):
#self.info(thumb,'delete')
if thumb in self.thumbs: self.thumbs.remove(thumb)
if thumb in self.ThumbContainer.subviews: self.ThumbContainer.remove_subview(thumb)
def layout(self):
if not self.ready: return
pass
# for drag and drop
def isOnMe(self, thumb):
ycenter = thumb.y + thumb.height/2
y0, y1 = self.y, self.y+self.height
return (y0 <= ycenter) and (ycenter < y1)
def isBelowMe(self, thumb):
ycenter = thumb.y + thumb.height/2
return (self.y+self.height <= ycenter)
def isAboveMe(self, thumb):
ycenter = thumb.y + thumb.height/2
return (ycenter < self.y)
# note: with send, drop and receive in the container, the thumb never has to know about bg
def sendToOverlay(self, thumb):
if self != bg : self.remove(thumb)
self.xyToGlobal(thumb)
#self.info(thumb, 'send')
bg.receive(thumb) # bg is the only receiver => not event needed here
thumb.bring_to_front()
def dropFromOverlay(self, thumb):
#self.info(thumb, 'drop')
bg.drop(thumb) # use an event because several containers may receive
def receive(self,thumb):
# check if the thumb is for me
if not self.isOnMe(thumb): return
#self.info(thumb, 'receive')
self.add(thumb)
bg.remove(thumb)
class Overlay(Container):
def __init__(self, *args, **kvargs):
self.ready = False
super(Overlay,self).setup(*args, **kvargs)
self.background_color = 0.1
self.ThumbClass = None # because the overlay receives any type
self.drop = EventHook()
self.grid = False
self.ready = True
self.layout()
def receive(self,thumb):
# check if the thumb is for me
if not self.isOnMe(thumb): return
#self.info(thumb, 'receive')
self.add(thumb)
class PageEditor(Container):
def __init__(self, *args, **kvargs):
self.ready = False
super(PageEditor,self).setup(*args, **kvargs)
self.pageSetup()
self.ThumbContainer = self.page
self.ThumbClass = EditorThumb
bg.drop += self.receive
self.ready = True
self.grid = True
self.layout()
def clear(self):
thumbs = list(self.thumbs)
i0 = photos1.getFirstVisibleThumbIndex()
for thumb in thumbs:
if thumb.saved : self.delete(thumb)
else: photos1.add(thumb, i0)
def anim(): photos1.layout()
ui.animate(anim,0.3)
def pageSetup(self):
page = ui.View()
page.w0, page.h0 = 56.3, 21.3 # define your page relative dimensions here
page.aspectRatio = page.w0 / page.h0
page.background_color = 0.1
sep = ui.View(background_color=0.2)
page.add_subview(sep)
page.sep = sep
page.saved = False
self.page = page
self.add_subview(self.page)
def layout(self):
if not self.ready: return
w = self.width
h = w / self.page.aspectRatio
y = (self.height - h)/2 # the page is centered in the frame
self.page.frame = (0, y, w, h)
self.page.sep.frame = (w/2-1, 0, 2, h)
def getThumbLocalOffset(self):
ox = self.x + self.ThumbContainer.x - bg.x
oy = self.y + self.ThumbContainer.y - bg.y
return ox,oy
def receive(self,thumb):
# check if the thumb is for me
if not self.isOnMe(thumb): return
#self.info(thumb, 'receive')
# 1/ find where to drop it
ox,oy = self.getThumbLocalOffset()
xDrop0 = thumb.x - ox
yDrop0 = thumb.y - oy
yDrop1 = max(yDrop0, 0)
yDrop1 = min(yDrop1, self.ThumbContainer.height - thumb.height)
# 2/ insert it with a smooth animatiom
def align():
thumb.ready = False
thumb.y += yDrop1-yDrop0
def setReady():
newThumb = self.add(thumb)
#newThumb.setSizeFromH(thumb.height)
newThumb.ready = True
if yDrop0!=yDrop1:
ui.animate(animation = align, duration = 0.2, completion = setReady)
else:
setReady()
bg.remove(thumb)
class PhotoPicker(Container):
def __init__(self, name, parentView, y, h, step=0, **kvargs):
self.ready = False
super(PhotoPicker,self).setup(name, parentView, y, h, **kvargs)
self.scrollviewSetup(h)
self.ThumbContainer = self.sv
self.ThumbClass = PhotoThumb
bg.drop += self.receive
self.step = step
self.ready = True
self.layout()
def scrollviewSetup(self, h):
self.sv = ui.ScrollView()
self.sv.background_color = 0.5
self.add_subview(self.sv)
self.enableScrollviewToInterceptTouches(True)
def enableScrollviewToInterceptTouches(self, boolean):
self.sv.scroll_enabled = boolean
def getFirstVisibleThumbIndex(self):
i0=-1
for i in range(len(self.thumbs)):
if self.thumbs[i].x > self.sv.content_offset.x:
i0=i
break
return i0
def initAssets(self, assets):
self.assets = assets
nbmax = 200
nbmax = min(nbmax, len(self.assets))
xc,yc = self.width/2, self.height/2
label = ui.Label(x=xc-100, y=yc-20, width=200, height=40, text_color='lightgreen')
self.add_subview(label)
self.ThumbContainer.hidden = True
for i in range(0,nbmax):
label.text = 'loading image {}'.format(i)
thumb = PhotoThumb(self, self.assets[i], self.height, name='thumb {}'.format(i))
self.thumbs.append(thumb)
self.ThumbContainer.add_subview(thumb)
self.remove_subview(label)
self.ThumbContainer.hidden = False
self.layout()
def getThumbLocalOffset(self):
ox = self.x + self.ThumbContainer.x - self.sv.content_offset.x - bg.x
oy = self.y + self.ThumbContainer.y - bg.y
return ox,oy
def getAlbum(self):
title = 'bretagne'
album = False
for a in photos.get_albums():
if a.title == title: album = a; break
if not album:
console.alert('album {} does not exist'.format(title))
return album.assets
def layout(self): # called automatically when the view size changes
if not self.ready: return
# 1/ adjust and realign thumbs
thumbs = self.thumbs
x = 0
for thumb in thumbs:
thumb.setSizeFromH(self.height)
#thumb.height = self.height
thumb.x = x
thumb.y = 0
x = x + thumb.width + self.step
# 2/ adjust scrollview
self.sv.content_size = (x,self.height)
# adjust content offset so the center doesnt move despite the resize
w0 = self.width/2
x0 = self.sv.content_offset.x + w0
zoom = self.height / self.sv.height
self.sv.content_offset = (x0 * zoom - w0, 0)
# define the scrollview size at the end!!
self.sv.frame = (0, 0, self.width, self.height)
def removeAnimation(self,thumb):
def anim(): self.layout()
ui.animate(anim,0.3)
def sendToOverlay(self, thumb):
self.xyToGlobal(thumb)
if self != bg : self.remove(thumb)
bg.receive(thumb) # bg is the only receiver => not event needed here
thumb.bring_to_front()
self.enableScrollviewToInterceptTouches(False)
def dropFromOverlay(self, thumb):
#self.info(thumb, 'drop')
bg.drop(thumb) # use an event because several containers may receive
self.enableScrollviewToInterceptTouches(True)
def receive(self,thumb):
# check if the thumb is for me
if not self.isOnMe(thumb): return
#self.info(thumb, 'receive')
# 1/ find where to insert it
ox,oy = self.getThumbLocalOffset()
xDrop = thumb.x - ox
thumbs = self.thumbs
iDrop = len(thumbs)
for i in range(len(thumbs)):
xEnd = thumbs[i].x + thumbs[i].width
if xEnd > xDrop:
if xDrop < thumbs[i].x + thumbs[i].width /2 : iDrop = i
else : iDrop = i+1
break
# 2/ insert it with a smooth animatiom
def align():
thumb.ready = False
newThumb = self.ThumbClass(self, thumb.asset, self.height, name=thumb.name)
newThumb.hidden = True
self.thumbs.insert( iDrop, newThumb)
self.ThumbContainer.add_subview(newThumb)
self.layout()
self.xyToGlobal(newThumb)
thumb.iv.flex = 'WH'
thumb.frame = newThumb.frame
self.xyToLocal(newThumb)
self.newThumb = newThumb
def setReady():
thumb.close()
self.newThumb.hidden = False
self.newThumb.ready = True
ui.animate(animation = align, duration = 0.3, completion = setReady)
bg.remove(thumb)
class Thumb(ui.View):
# a view and an imageView inside, remember its asset
def __init__(self, top, asset, h, **kvargs):
self.ready = False
super(Thumb,self).__init__(**kvargs)
self.border_color, self.border_width, self.top, self.asset = 'black', 1, top, asset
self.ivSetup(asset)
self.aspectRatio = self.iv.aspectRatio # initially this is true, then it may change (crop)
self.setSizeFromH(h)
w1,h1 = self.iv.imgSize
self.scale = self.height / h1
self.iv.scale = self.scale
self.dragging = False
self.ready = True
self.saved = False
self.layout() # nb: ready must be true!
def ivSetup(self, asset):
img = self.getImage(asset)
iv = ui.ImageView()
iv.image = img
iv.imgSize = img.size
w1, h1= iv.imgSize
iv.aspectRatio = w1 / h1
self.iv = iv
self.add_subview(self.iv)
def getImage(self, asset): return self.getImageSmall(asset)
def getImageSmall(self, asset): return self.getImageHeight(asset, 200)
def getImageBig(self, asset): return self.getImageHeight(asset, 600)
def getImageHeight(self, asset, h):
w0, h0 = asset.pixel_width , asset.pixel_height
if h>h0: w,h = w0,h0
else: w = int(h * w0 / h0)
img = asset.get_ui_image((w,h)).with_rendering_mode(ui.RENDERING_MODE_ORIGINAL)
return img
def layout(self): # needed for image crop
if not self.ready: return # just to avoid errors while initializing
self.iv.frame = (0, 0, self.width, self.height)
def setSizeFromH(self, h):
try:
if type(self)==EditorThumb: self.infoPrint('selfSizeFromH')
except: pass
self.height = h
self.width = int(h * self.aspectRatio)
def info(self, txt):
if tw: print('{} {} from {} at x,y = {} , {}'.format(
self.name, txt, self.top.name, self.x, self.y))
def infoPrint(self, txt):
if tw: print(txt)
# these actions send, drag, drop CAN be modified by subclasses
def send(self, touch):
self.top.sendToOverlay(self)
def drag(self, touch):
dx,dy = self.getTouch_dxdy(touch)
self.move(dx,dy)
def drop(self, touch):
self.top.dropFromOverlay(self)
def close(self):
self.top.delete(self)
def horizontalMove(self, touch):
dx,dy = self.getTouch_dxdy(touch)
if self.width < bg.width : return
x = self.x + dx
x = min( x , 0)
x = max( x , bg.width - self.width)
self.x = x
def doNothing(self, touch): pass
# these low level actions should NOT be modified by subclasses
def touch_began(self, touch):
if not self.ready: return
self.infoPrint('')
self.info('touch began')
self.touch0 = touch.location
self.send(touch)
menu.selectThumb(self)
finger.moveToTouch(touch, self)
def touch_ended(self, touch):
if not self.ready: return
self.touch0 = None
self.drop(touch)
finger.moveToTouch(touch, self)
def touch_moved(self, touch):
if not self.ready: return
self.drag(touch)
finger.moveToTouch(touch, self)
def getTouch_dxdy(self, touch):
x0,y0 = touch.prev_location
x,y = touch.location
dx,dy = x-x0, y-y0
return dx,dy
def move(self, dx, dy):
self.x += dx
self.y += dy
class HighResThumb(Thumb):
def getImage(self, asset): return self.getImageHeight(asset, 1200)
class PhotoThumb(Thumb):
def send(self, touch):
x,y = touch.location
edge = 0.33
if y < self.height*edge or y > self.height*(1-edge): # move me...
self.dragging = True
self.previousTop = self.top
self.previousTop.enableScrollviewToInterceptTouches(False)
self.top.sendToOverlay(self)
else: # ... or move container
self.dragging = False
self.top.enableScrollviewToInterceptTouches(True)
def drag(self, touch):
if self.dragging:
dx,dy = self.getTouch_dxdy(touch)
self.move(dx,dy)
def drop(self, touch):
if self.dragging:
self.dragging = False
self.top.dropFromOverlay(self)
self.previousTop.enableScrollviewToInterceptTouches(True)
class EditorThumb(Thumb):
def ivSetup(self, asset):
super(EditorThumb,self).ivSetup(asset)
iv = self.iv
w1, h1= iv.imgSize
iv.frame = (0,0,w1,h1)
iv.x = 0
iv.y = 0
iv.imgCrop = (0,0,0,0)
self.codes ={'move':[4], 'resize':[0,2,6,8], 'crop':[1,3,5,7]}
self.scaleChange = 1
# a high resolution image that can be crpped and zoomed
def getImage(self, asset): return self.getImageBig(asset)
def send(self, touch):
self.dragging = False
self.initialTouchCode = self.getTouchCode(touch)
self.top.sendToOverlay(self)
def drag(self, touch):
self.moveOrResizeOrCrop(touch)
def drop(self, touch):
self.top.dropFromOverlay(self)
if self.dragging:
self.dragging = False
def cropLayout(self):
w,h = self.iv.imgSize
l, t, r, b = self.iv.imgCrop
s = self.iv.scale
self.iv.width = self.width + l*s + r*s
self.iv.height = self.height + t*s + b*s
self.iv.x = -l*s
self.iv.y = -t*s
self.iv.scale = self.iv.height / h
def layout(self): # needed for image crop
if not self.ready: return # just to avoid errors while initializing
w,h = self.iv.imgSize
l, t, r, b = self.iv.imgCrop
self.iv.scale *= self.scaleChange
self.scaleChange = 1
s = self.iv.scale
self.iv.width = self.width + l*s + r*s
self.iv.height = self.height + t*s + b*s
self.iv.x = -l*s
self.iv.y = -t*s
def resize(self, dw, dh):
h = self.height
s = (h+dh)/h
self.height *= s
self.width *= s
self.scale *= s
self.scaleChange = s
#self.normalLayout()
def crop(self, dl, dt, dr, db):
# scale is constant
#self.layout = self.cropLayout
s = self.iv.scale
l, t, r, b = self.iv.imgCrop
l, t, r, b = l*s, t*s, r*s, b*s
dl = max(0, l+dl) - l
dt = max(0, t+dt) - t
dr = max(0, r+dr) - r
db = max(0, b+db) - b
self.x += dl
self.y += dt
self.width -= dl + dr
self.height -= dt + db
l, t, r, b = l+dl, t+dt, r+dr, b+db
l, t, r, b = l/s, t/s, r/s, b/s
self.iv.imgCrop = (l, t, r, b)
self.cropLayout()
def minWHchange(self,dw,dh):
w0,h0 = self.width, self.height
# keep aspect ratio
ds = (dw/w0 + dh/h0)/2
dw,dh = w0*ds, h0*ds
dmax = 10 # limit size change
d = max(abs(dw), abs(dh))
if d>dmax:
s = dmax/d
dw, dh = dw*s, dh*s
return dw,dh
def moveOrResizeOrCrop(self, touch):
# the touchcan resize or crop, depending on the touched region
code = self.initialTouchCode
# 0 1 2 this encoding of the touch position makes the tests simpler
# 3 4 5
# 6 7 8
dx,dy = self.getTouch_dxdy(touch)
w,h, s = self.width, self.height, 1
w1,h1 = self.iv.imgSize
# moving touch
if code == 4: # center touch
self.move(dx,dy)
# resizing touches
elif code == 8: # bottom right corner touch
dw, dh = self.minWHchange(dx,dy)
self.resize(dw, dh)
elif code == 2: # top right corner touch
dw, dh = self.minWHchange(dx,-dy)
self.resize(dw, dh)
self.move(0, -dh)
elif code == 6: # bottom left corner touch
dw, dh = self.minWHchange(-dx,dy)
self.move(-dw, 0)
self.resize(dw, dh)
elif code == 0: # top left corner touch
dw, dh = self.minWHchange(-dx,-dy)
self.move(-dw, -dh)
self.resize(dw, dh)
# croping touches
elif code == 1: # top touch
self.crop(dl=0, dt=dy, dr=0, db=0)
elif code == 5: # right touch
self.crop(dl=0, dt=0, dr=-dx, db=0)
elif code == 3: # left touch
self.crop(dl=dx, dt=0, dr=0, db=0)
elif code == 7: # bottom touch
self.crop(dl=0, dt=0, dr=0, db=-dy)
def getTouchCode(self, touch):
# the touchcan resize or crop, depending on the touched region
x,y = touch.location
w,h = self.width, self.height
x0, x1, y0, y1 = min(0.3*w,50) , max(0.7*w,w-50), min(0.3*h,50), max(0.7*h,h-50)
code = ((x0<x)*1 + (x1<x)*1) + ((y0<y)*1 + (y1<y)*1)*3
# 0 1 2 this encoding of the touch position makes the tests simpler
# 3 4 5
# 6 7 8
return code
class Menu(ui.View):
def __init__(self):
self.background_color = 0.5
self.frame = (0,0, bg.width, 50)
self.button_d = 32
self.button_y = 12
self.button_w = 32
self.button_h = 32
self.leftOffset = 0
self.rightOffset = bg.width
self.selectedThumb = None
end_button = self.newButton('left', 'iow:close_circled_32')
end_button.action = self.end_button_action
self.end_button = end_button
info_button = self.newButton('left', 'iow:help_circled_32')
info_button.action = self.info_button_action
self.info_button = info_button
save_button = self.newButton('right', 'iow:ios7_camera_32')
save_button.action = self.save_button_action
self.save_button = save_button
clear_button = self.newButton('right', 'iow:refresh_32')
clear_button.action = self.clear_button_action
self.clear_button = clear_button
self.rightOffset -= 100
bigger_button = self.newButton('right', 'iow:arrow_expand_32')
bigger_button.action = self.bigger_button_action
self.bigger = bigger_button
self.bigger.active = False
image_button = self.newButton('right', 'iow:image_32')
image_button.action = self.bigger_button_action
image_button.flex = 'WH'
self.image_button = image_button
bg.add_subview(self)
def getIcon(self,icon): return ui.Image(icon).with_rendering_mode(ui.RENDERING_MODE_ORIGINAL)
def newButton(self, side, icon=''):
b = ui.Button()
b.image = self.getIcon(icon)
b.width = self.button_w
b.height = self.button_h
b.y = self.button_y
if side == 'left':
x = self.leftOffset + self.button_d
self.leftOffset += self.button_d + b.width
else:
x = self.rightOffset - self.button_d - b.width
self.rightOffset = x
b.x = x
b.enabled = True
self.add_subview(b)
return b
def end_button_action(self,sender):
finger.moveToButton(self.end_button)
bg.close()
def save_button_action(self,sender):
finger.moveToButton(self.save_button)
save(editor.page, outputAlbum1, outputAlbum2, editor.thumbs)
def clear_button_action(self,sender):
finger.moveToButton(self.clear_button)
editor.clear()
def bigger_button_action(self,sender):
finger.moveToButton(self.bigger)
if not self.selectedThumb: return
if self.bigger.active:
self.bigger.active = False
self.bigger.image = self.getIcon('iow:arrow_expand_32')
self.bigThumb.close()
else:
self.bigger.active = True
self.bigger.image = self.getIcon('iow:arrow_shrink_32')
thumb = HighResThumb(bg, self.selectedThumb.asset, h = bg.height-photos2.y)
thumb.send = thumb.doNothing
thumb.drag = thumb.horizontalMove
thumb.drop = thumb.doNothing
thumb.y = photos2.y
thumb.x = bg.width / 2 - thumb.width / 2
bg.add(thumb)
self.bigThumb = thumb
def info_button_action(self, sender):
url = 'https://youtu.be/zs38yqBNbwg'
#webbrowser.open(url, modal=True)
webbrowser.get('safari').open(url)
def selectThumb(self, thumb):
self.selectedThumb = thumb
b = self.image_button
b.image = None
img = thumb.getImageHeight(thumb.asset, 32)
b.background_image = img
w,h = img.size
b.width = w / h * b.height
b.x = self.bigger.x - b.width - self.button_d
def Finger(bg):
finger = ui.ImageView()
iconeOff = 'emj:Raised_Hand'
iconeOn = 'emj:Index_Finger_Up_1'
finger.imageOff= ui.Image(iconeOff).with_rendering_mode(ui.RENDERING_MODE_ORIGINAL)
finger.imageOn= ui.Image(iconeOn).with_rendering_mode(ui.RENDERING_MODE_ORIGINAL)
finger.image = finger.imageOff
finger.frame = (0, 0, 100, 100)
finger.alpha = 0
finger.touch_enabled = False
def moveToButton(b):
if finger.alpha == 0: return
x0,y0 = 16,16
x = b.x - 40 + x0
y = b.y - 10 + y0
def move() :
finger.move(x,y)
finger.alpha = 1
def press():
finger.image = finger.imageOn
ui.delay(up, 0.5)
def up():
finger.alpha = 0.5
finger.image = finger.imageOff
ui.animate(move, 0.2, 0, press)
finger.moveToButton = moveToButton
def moveToTouch(touch, thumb):
if finger.alpha == 0: return
try: x0,y0 = thumb.top.getThumbLocalOffset()
except: x0,y0 = 0,0
x,y = touch.location
x = x - 40 + x0 + thumb.x
y = y - 10 + y0 + thumb.y
if touch.phase == 'moved': finger.move(x,y)
if touch.phase == 'began':
def anim() :
finger.move(x,y)
finger.alpha = 1
def finish():
finger.image = finger.imageOn
ui.animate(anim, 0.2, 0, finish)
if touch.phase == 'ended':
def anim() :
#finger.move(bg.width-100, bg.height/3)
finger.alpha = 0.5
ui.animate(anim, 0.2)
finger.image = finger.imageOff
finger.bring_to_front()
finger.moveToTouch = moveToTouch
def move(x,y):
finger.x = x
finger.y = y
finger.move = move
bg.add_subview(finger)
move(bg.width/2, bg.height/2)
return finger
class App():
def __init__(self):
# global events
#cloud = EventHook()
# app top view
global bg, pages, editor, photos1, photos2, menu
bg = Overlay(TOP, background_color='gray')
#bg.drag = EventHook() # when an object starts being dragged
#bg.drop = EventHook() # when an object is dropped
bg.present(hide_title_bar=True)
# for tests
global tw
# the photo containers
w,h = ui.get_screen_size()
photos2 = PhotoPicker(PHOTOS2, bg, 50, 100, step=4)
editor = PageEditor( EDITOR, bg, 150, h-300)
photos1 = PhotoPicker(PHOTOS1, bg, h-150, 150)
#photos1 = PhotoPicker(PHOTOS1, bg, h-300, 150)
#photos2 = PhotoPicker(PHOTOS2, bg, h-150, 150)
global outputAlbum1, outputAlbum2
photoAssets, pageAssets, outputAlbum1, outputAlbum2 = getAssets()
photos1.initAssets(photoAssets)
photos2.initAssets(pageAssets)
# create sensors between containers and link their position to container edges
topSplitter = Splitter('topSplitter', bg, editor.y, ymin=100, ymax=h-100)
botSplitter = Splitter('botSplitter', bg, photos1.y, ymin=100, ymax=h-100)
topSplitter.moving += photos2.moveLowerEdge
topSplitter.moving += editor.moveUpperEdge
botSplitter.moving += editor.moveLowerEdge
botSplitter.moving += photos1.moveUpperEdge
menu = Menu()
global finger
finger = Finger(bg)
#finger.alpha = 1 # activates the finger
#tw = TextWindow((0, 10, 400, 700))
if tw: tw.bring_to_front()
class TextWindow(ui.View):
def __init__(self, frame):
self.touch_enabled = False
self.frame = frame
self.background_color = (0,0,0,0)
console_view = ui.TextView(name='console_view')
self.lines = []
#console_view = ui.ListDataSource(self.lines)
self.console_view = console_view
console_view.border_width = 1
console_view.frame = self.frame
console_view.flex = 'wh'
console_view.background_color = (0,0,0, 0.2)
console_view.text_color = 'lightgreen'
self.add_subview(console_view)
bg.add_subview(self)
global print
print = self.print
console.print = self.print
print('console ready')
def print(self,txt):
lines = self.lines
lines.append(txt)
if len(lines)>40:
lines.remove(lines[0])
str = ''
for txt in lines: str += txt+'\n'
self.console_view.text = str
class EventHook(object):
def __init__(self, **kwargs):
self.documentation = kwargs # named parameters should be: param='explaination'
self.keys = kwargs.keys() # the parameters should be named and defined clearly
self.__handlers = []
def __iadd__(self, handler):
self.__handlers.append(handler)
return self
def __isub__(self, handler):
self.__handlers.remove(handler)
return self
def __call__(self, *args, **kwargs):
for key in kwargs.keys():
if not key in self.keys:
print('{} is not a valid parameter'.format(key))
for handler in self.__handlers:
handler(*args, **kwargs)
def removeObject(self, inObject):
# for bound methods obj.meth, remove it via 'obj' (usefull when deleting an object)
for theHandler in self.__handlers:
try:
# note pyhton2: theHandler.im_self
# note pyhton3: theHandler.__self__
if theHandler.__self__ == inObject:
self -= theHandler
except:
pass
if __name__ == "__main__":
console.clear()
app = App()
test = False
if test:
thumb1= Thumb(bg, photos1.thumbs[0].asset, x=400, y=0 , name='thumb1')
photos2.receive(thumb1)
thumb2 = Thumb(bg, photos1.thumbs[4].asset, x=400, y=200 , name='thumb2')
bg.receive(thumb2)
thumb3 = EditorThumb(bg, photos1.thumbs[2].asset, x=400, y=400, name='thumb3')
editor.receive(thumb3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment