wasp: launcher: Experimental launcher implementation
It is not really the launcher itself that is immature. Rather that the framework and UI concepts to move between applications isn't complete yet.pull/24/head
parent
59bb70fa64
commit
8ed80eeeba
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 965 B |
Binary file not shown.
After Width: | Height: | Size: 599 B |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 820 B |
Binary file not shown.
After Width: | Height: | Size: 593 B |
|
@ -3,6 +3,7 @@
|
|||
|
||||
import wasp
|
||||
|
||||
import icons
|
||||
import fonts.clock as digits
|
||||
|
||||
DIGITS = (
|
||||
|
@ -25,6 +26,8 @@ class ClockApp():
|
|||
|
||||
Shows a time (as HH:MM) together with a battery meter and the date.
|
||||
"""
|
||||
NAME = 'Clock'
|
||||
ICON = icons.clock
|
||||
|
||||
def __init__(self):
|
||||
self.meter = wasp.widgets.BatteryMeter()
|
||||
|
|
|
@ -3,11 +3,15 @@
|
|||
|
||||
import wasp
|
||||
|
||||
import icons
|
||||
|
||||
class FlashlightApp(object):
|
||||
"""Trivial flashlight application.
|
||||
|
||||
Shows a pure white screen with the backlight set to maximum.
|
||||
"""
|
||||
NAME = 'Torch'
|
||||
ICON = icons.torch
|
||||
|
||||
def foreground(self):
|
||||
"""Activate the application."""
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
# Copyright (C) 2020 Daniel Thompson
|
||||
|
||||
import wasp
|
||||
import icons
|
||||
|
||||
class LauncherApp():
|
||||
"""An application launcher application.
|
||||
"""
|
||||
NAME = 'Launcher'
|
||||
ICON = icons.app
|
||||
|
||||
def foreground(self):
|
||||
"""Activate the application."""
|
||||
self._page = 0
|
||||
self._draw()
|
||||
wasp.system.request_event(wasp.EventMask.TOUCH |
|
||||
wasp.EventMask.SWIPE_UPDOWN)
|
||||
|
||||
def swipe(self, event):
|
||||
i = self._page
|
||||
n = self._num_pages
|
||||
if event[0] == wasp.EventType.UP:
|
||||
i += 1
|
||||
if i >= n:
|
||||
i -= 1
|
||||
wasp.watch.vibrator.pulse()
|
||||
return
|
||||
else:
|
||||
i -= 1
|
||||
if i < 0:
|
||||
wasp.system.switch(wasp.system.applications[0])
|
||||
return
|
||||
|
||||
self._page = i
|
||||
wasp.watch.display.mute(True)
|
||||
self._draw()
|
||||
wasp.watch.display.mute(False)
|
||||
|
||||
def touch(self, event):
|
||||
page = self._get_page(self._page)
|
||||
x = event[1]
|
||||
y = event[2]
|
||||
app = page[2 * (y // 120) + (x // 120)]
|
||||
if app:
|
||||
wasp.system.switch(app)
|
||||
else:
|
||||
wasp.watch.vibrator.pulse()
|
||||
|
||||
@property
|
||||
def _num_pages(self):
|
||||
"""Work out what the highest possible pages it."""
|
||||
num_apps = len(wasp.system.applications)
|
||||
return (num_apps + 3) // 4
|
||||
|
||||
def _get_page(self, i):
|
||||
apps = wasp.system.applications
|
||||
page = apps[4*i: 4*(i+1)]
|
||||
while len(page) < 4:
|
||||
page.append(None)
|
||||
return page
|
||||
|
||||
def _draw(self):
|
||||
"""Redraw the display from scratch."""
|
||||
def draw_app(app, x, y):
|
||||
if not app:
|
||||
return
|
||||
draw.set_color(0xffff)
|
||||
draw.rleblit(app.ICON, (x+13, y+12))
|
||||
draw.set_color(0xbdb6)
|
||||
draw.string(app.NAME, x, y+120-30, 120)
|
||||
|
||||
draw = wasp.watch.drawable
|
||||
page = self._get_page(self._page)
|
||||
|
||||
draw.fill()
|
||||
draw_app(page[0], 0, 0)
|
||||
draw_app(page[1], 120, 0)
|
||||
draw_app(page[2], 0, 120)
|
||||
draw_app(page[3], 120, 120)
|
|
@ -3,10 +3,13 @@
|
|||
|
||||
import machine
|
||||
import wasp
|
||||
import icons
|
||||
|
||||
class TestApp():
|
||||
"""Simple test application.
|
||||
"""
|
||||
NAME = 'Self Test'
|
||||
ICON = icons.app
|
||||
|
||||
def __init__(self):
|
||||
self.tests = ('Touch', 'String', 'Button', 'Crash')
|
||||
|
@ -57,6 +60,7 @@ class TestApp():
|
|||
def benchmark_string(self):
|
||||
draw = wasp.watch.drawable
|
||||
draw.fill(0, 0, 30, 240, 240-30)
|
||||
self.scroll.draw()
|
||||
t = machine.Timer(id=1, period=8000000)
|
||||
t.start()
|
||||
draw.string("The quick brown", 12, 24+24)
|
||||
|
|
|
@ -5,8 +5,9 @@ freeze('.', 'watch.py', opt=3)
|
|||
freeze('../..',
|
||||
(
|
||||
'apps/clock.py',
|
||||
'apps/testapp.py',
|
||||
'apps/flashlight.py',
|
||||
'apps/launcher.py',
|
||||
'apps/testapp.py',
|
||||
'boot.py',
|
||||
'demo.py',
|
||||
'draw565.py',
|
||||
|
|
|
@ -4,6 +4,15 @@
|
|||
# 1-bit RLE, generated from res/battery.png, 189 bytes
|
||||
battery = (36, 48, b'\x97\x0e\x14\x12\x11\x14\x10\x14\x0c\x08\x0c\x08\x08\x08\x0c\x08\x08\x08\x0c\x08\x08\x08\x0c\x08\x08\x04\x14\x04\x08\x04\x14\x04\x08\x04\x0c\x04\x04\x04\x08\x04\x0b\x05\x04\x04\x08\x04\n\x06\x04\x04\x08\x04\t\x07\x04\x04\x08\x04\x08\x07\x05\x04\x08\x04\x07\x07\x06\x04\x08\x04\x06\x07\x07\x04\x08\x04\x05\x07\x08\x04\x08\x04\x04\x0e\x02\x04\x08\x04\x03\x0f\x02\x04\x08\x04\x02\x10\x02\x04\x08\x04\x02\x10\x02\x04\x08\x04\x02\x0f\x03\x04\x08\x04\x02\x0e\x04\x04\x08\x04\x08\x07\x05\x04\x08\x04\x07\x07\x06\x04\x08\x04\x06\x07\x07\x04\x08\x04\x05\x07\x08\x04\x08\x04\x04\x07\t\x04\x08\x04\x04\x06\n\x04\x08\x04\x04\x05\x0b\x04\x08\x04\x04\x04\x0c\x04\x08\x04\x14\x04\x08\x04\x14\x04\x08\x04\x14\x04\x08\x04\x14\x04\x08\x1c\x08\x1c\x08\x1c\x08\x1c\x98')
|
||||
|
||||
# 1-bit RLE, generated from res/app_icon.png, 441 bytes
|
||||
app = (96, 64, b'\x1e$<$<$;&\x97,20/2-4,\x03.\x03,\x03.\x03,\x03.\x03,\x03.\x03,\x03.\x03,\x03\x0c\x03\x10\x03\x0c\x03,\x03\n\x07\x0c\x07\n\x03,\x03\t\x03\x02\x04\n\x04\x02\x03\t\x03,\x03\x08\x02\x07\x02\x08\x02\x07\x02\x08\x03,\x03\x07\x02\t\x02\x06\x02\t\x02\x07\x03,\x03\x06\x02\x0b\x02\x04\x02\x0b\x02\x06\x03,\x03\x06\x02\x0b\x02\x04\x02\x0b\x02\x06\x03,\x03\x05\x02\x0c\x02\x04\x02\x0c\x02\x05\x03,\x03\x05\x02\x0c\x02\x04\x02\x0c\x02\x05\x03,\x03\x05\x03\x0b\x02\x04\x02\x0b\x03\x05\x03,\x03\x06\x02\x0b\x02\x04\x02\x0b\x02\x06\x03,\x03\x06\x02\x0b\x02\x04\x02\x0b\x01\x07\x03,\x03\x07\x02\n\x02\x04\x02\n\x02\x07\x03+\x04\x08\x02\t\x02\x04\x02\t\x02\x08\x03*\x05\t\x0c\x04\x0c\t\x03*\x05\n\x0b\x04\x0b\n\x03*\x05.\x03*\x05.\x03*\x05.\x03*\x05.\x03*\x05\n\x0b\x04\x0b\n\x03+\x04\t\x0c\x04\x0c\t\x03,\x03\x08\x02\t\x02\x04\x02\t\x02\x08\x03,\x03\x07\x02\n\x02\x04\x02\n\x02\x07\x03,\x03\x06\x02\x0b\x02\x04\x02\x0b\x01\x07\x03,\x03\x06\x02\x0b\x02\x04\x02\x0b\x02\x06\x03,\x03\x05\x03\x0b\x02\x04\x02\x0b\x03\x05\x03,\x03\x05\x02\x0c\x02\x04\x02\x0c\x02\x05\x03,\x03\x05\x02\x0c\x02\x04\x02\x0c\x02\x05\x03,\x03\x06\x02\x0b\x02\x04\x02\x0b\x02\x06\x03,\x03\x06\x02\x0b\x02\x04\x02\x0b\x02\x06\x03,\x03\x07\x02\t\x02\x06\x02\t\x02\x07\x03,\x03\x08\x02\x07\x02\x08\x02\x07\x02\x08\x03,\x03\t\x03\x02\x04\n\x04\x02\x03\t\x03,\x03\n\x06\x0e\x06\n\x03,\x03\x0c\x03\x10\x03\x0c\x03,\x03.\x03,\x03.\x03,\x03.\x03,\x03.\x03,\x03.\x03,4-2/02,\x97&;$<$<$\x1e')
|
||||
|
||||
# 1-bit RLE, generated from res/clock_icon.png, 301 bytes
|
||||
clock = (96, 64, b'\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xcd\x06\r\x06!\x05\x0b\x08\x0c\x08\x0b\n\x1d\t\x07\x0c\n\x08\n\x0c\x1b\x0b\x06\x0e\x08\x03\x02\x03\n\x04\x05\x04\x1a\x04\x03\x04\x06\x02\x08\x04\r\x03\t\x04\x07\x03\x19\x04\x05\x04\x10\x04\x0c\x03\t\x03\t\x02\x19\x03\x07\x03\x11\x03\x0c\x03\t\x03\t\x03\n\x04\t\x04\x07\x04\x10\x03\x0c\x03\t\x03\t\x03\n\x04\t\x03\t\x03\x10\x03\x0c\x03\t\x03\t\x03\n\x04\t\x03\t\x03\x10\x03\x0c\x03\t\x04\x07\x04\n\x04\t\x03\t\x03\x0f\x04\x0c\x03\n\x04\x05\x05\n\x04\t\x03\x03\x02\x04\x03\x0e\x04\r\x03\n\n\x01\x03\x17\x03\x02\x04\x03\x03\r\x05\r\x03\x0b\t\x01\x03\x17\x03\x02\x03\x04\x03\x0c\x05\x0e\x03\r\x05\x03\x03\x17\x03\t\x03\x0b\x05\x0f\x03\x15\x03\x17\x03\t\x03\n\x05\x10\x03\x14\x04\x17\x03\t\x03\t\x05\x11\x03\x14\x03\x18\x04\x07\x04\x08\x04\x13\x03\x14\x03\x19\x03\x07\x03\x08\x04\x14\x03\x13\x04\x0b\x04\n\x03\x06\x04\x07\x04\x15\x03\x0b\x01\x05\x05\x0c\x04\x0b\x04\x03\x04\x07\x03\x12\r\x06\n\r\x04\x0b\x0b\x06\x0f\x07\r\x06\t\x0e\x04\x0c\t\x07\x0f\x07\r\x07\x06\x10\x04\x0e\x05\t\x0f\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xaa')
|
||||
|
||||
# 1-bit RLE, generated from res/torch_icon.png, 283 bytes
|
||||
torch = (96, 64, b'\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00e\x06W\nT\x04\x06\x02S\x03\x07\x02S\x02\n\x01\x0b\x029\x05\x08\x02\t\x02\x08\x03:\x07\x06\x02\x0b\x01\x06\x02$(\n\x02\x03\x03%(\x0c\x01+\x02%\x01\x0b\x02+\x02%\x01\x0c\x01+\x02\x05\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x05\x01\x0b\x02+\x02\x04\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x04\x01\x0c\x01+\x02%\x01\x0b\x02\x03\n\x1e\x02\x05\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x05\x01\x0c\x01+\x02\x04\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x04\x01\x0b\x02+\x02%\x01\x0c\x01+\x02%\x01\x0b\x02+(\x0c\x01,(\n\x02\x03\x03L\x02\x0b\x01\x06\x02K\x02\t\x02\x08\x03H\x02\n\x01\x0b\x02G\x03\x07\x02U\x04\x06\x02V\nY\x06\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xe2')
|
||||
|
||||
# 1-bit RLE, generated from res/up_arrow.png, 16 bytes
|
||||
up_arrow = (16, 9, b'\x07\x02\r\x04\x0b\x06\t\x08\x07\n\x05\x0c\x03\x0e\x01 ')
|
||||
|
||||
|
|
34
wasp/wasp.py
34
wasp/wasp.py
|
@ -15,6 +15,7 @@ import widgets
|
|||
|
||||
from apps.clock import ClockApp
|
||||
from apps.flashlight import FlashlightApp
|
||||
from apps.launcher import LauncherApp
|
||||
from apps.testapp import TestApp
|
||||
|
||||
class EventType():
|
||||
|
@ -86,6 +87,8 @@ class Manager():
|
|||
self.applications = []
|
||||
self.blank_after = 15
|
||||
self.charging = True
|
||||
self.launcher = LauncherApp()
|
||||
|
||||
self._brightness = 2
|
||||
self._button = PinHandler(watch.button)
|
||||
|
||||
|
@ -142,23 +145,40 @@ class Manager():
|
|||
quick application ring. Applications on the ring are not permitted
|
||||
to subscribe to :py:data`EventMask.SWIPE_LEFTRIGHT` events.
|
||||
|
||||
Swipe up is used to bring up the launcher. Clock applications are not
|
||||
permitted to subscribe to :py:data`EventMask.SWIPE_UPDOWN` events since
|
||||
they should expect to be the default application (and is important that
|
||||
we can trigger the launcher from the default application).
|
||||
|
||||
:param int direction: The direction of the navigation
|
||||
"""
|
||||
app_list = self.applications
|
||||
|
||||
if direction == EventType.LEFT:
|
||||
i = app_list.index(self.app) + 1
|
||||
if i >= len(app_list):
|
||||
if self.app in app_list:
|
||||
i = app_list.index(self.app) + 1
|
||||
if i >= len(app_list):
|
||||
i = 0
|
||||
else:
|
||||
i = 0
|
||||
self.switch(app_list[i])
|
||||
elif direction == EventType.RIGHT:
|
||||
i = app_list.index(self.app) - 1
|
||||
if i < 0:
|
||||
i = len(app_list)-1
|
||||
if self.app in app_list:
|
||||
i = app_list.index(self.app) - 1
|
||||
if i < 0:
|
||||
i = len(app_list)-1
|
||||
else:
|
||||
i = 0
|
||||
self.switch(app_list[i])
|
||||
elif direction == EventType.UP:
|
||||
self.switch(self.launcher)
|
||||
elif direction == EventType.DOWN:
|
||||
if self.app != app_list[0]:
|
||||
self.switch(app_list[0])
|
||||
else:
|
||||
watch.vibrator.pulse()
|
||||
elif direction == EventType.HOME:
|
||||
i = app_list.index(self.app)
|
||||
if i != 0:
|
||||
if self.app != app_list[0]:
|
||||
self.switch(app_list[0])
|
||||
else:
|
||||
self.sleep()
|
||||
|
|
Loading…
Reference in New Issue