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 wasp
|
||||||
|
|
||||||
|
import icons
|
||||||
import fonts.clock as digits
|
import fonts.clock as digits
|
||||||
|
|
||||||
DIGITS = (
|
DIGITS = (
|
||||||
|
@ -25,6 +26,8 @@ class ClockApp():
|
||||||
|
|
||||||
Shows a time (as HH:MM) together with a battery meter and the date.
|
Shows a time (as HH:MM) together with a battery meter and the date.
|
||||||
"""
|
"""
|
||||||
|
NAME = 'Clock'
|
||||||
|
ICON = icons.clock
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.meter = wasp.widgets.BatteryMeter()
|
self.meter = wasp.widgets.BatteryMeter()
|
||||||
|
|
|
@ -3,11 +3,15 @@
|
||||||
|
|
||||||
import wasp
|
import wasp
|
||||||
|
|
||||||
|
import icons
|
||||||
|
|
||||||
class FlashlightApp(object):
|
class FlashlightApp(object):
|
||||||
"""Trivial flashlight application.
|
"""Trivial flashlight application.
|
||||||
|
|
||||||
Shows a pure white screen with the backlight set to maximum.
|
Shows a pure white screen with the backlight set to maximum.
|
||||||
"""
|
"""
|
||||||
|
NAME = 'Torch'
|
||||||
|
ICON = icons.torch
|
||||||
|
|
||||||
def foreground(self):
|
def foreground(self):
|
||||||
"""Activate the application."""
|
"""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 machine
|
||||||
import wasp
|
import wasp
|
||||||
|
import icons
|
||||||
|
|
||||||
class TestApp():
|
class TestApp():
|
||||||
"""Simple test application.
|
"""Simple test application.
|
||||||
"""
|
"""
|
||||||
|
NAME = 'Self Test'
|
||||||
|
ICON = icons.app
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.tests = ('Touch', 'String', 'Button', 'Crash')
|
self.tests = ('Touch', 'String', 'Button', 'Crash')
|
||||||
|
@ -57,6 +60,7 @@ class TestApp():
|
||||||
def benchmark_string(self):
|
def benchmark_string(self):
|
||||||
draw = wasp.watch.drawable
|
draw = wasp.watch.drawable
|
||||||
draw.fill(0, 0, 30, 240, 240-30)
|
draw.fill(0, 0, 30, 240, 240-30)
|
||||||
|
self.scroll.draw()
|
||||||
t = machine.Timer(id=1, period=8000000)
|
t = machine.Timer(id=1, period=8000000)
|
||||||
t.start()
|
t.start()
|
||||||
draw.string("The quick brown", 12, 24+24)
|
draw.string("The quick brown", 12, 24+24)
|
||||||
|
|
|
@ -5,8 +5,9 @@ freeze('.', 'watch.py', opt=3)
|
||||||
freeze('../..',
|
freeze('../..',
|
||||||
(
|
(
|
||||||
'apps/clock.py',
|
'apps/clock.py',
|
||||||
'apps/testapp.py',
|
|
||||||
'apps/flashlight.py',
|
'apps/flashlight.py',
|
||||||
|
'apps/launcher.py',
|
||||||
|
'apps/testapp.py',
|
||||||
'boot.py',
|
'boot.py',
|
||||||
'demo.py',
|
'demo.py',
|
||||||
'draw565.py',
|
'draw565.py',
|
||||||
|
|
|
@ -4,6 +4,15 @@
|
||||||
# 1-bit RLE, generated from res/battery.png, 189 bytes
|
# 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')
|
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
|
# 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 ')
|
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.clock import ClockApp
|
||||||
from apps.flashlight import FlashlightApp
|
from apps.flashlight import FlashlightApp
|
||||||
|
from apps.launcher import LauncherApp
|
||||||
from apps.testapp import TestApp
|
from apps.testapp import TestApp
|
||||||
|
|
||||||
class EventType():
|
class EventType():
|
||||||
|
@ -86,6 +87,8 @@ class Manager():
|
||||||
self.applications = []
|
self.applications = []
|
||||||
self.blank_after = 15
|
self.blank_after = 15
|
||||||
self.charging = True
|
self.charging = True
|
||||||
|
self.launcher = LauncherApp()
|
||||||
|
|
||||||
self._brightness = 2
|
self._brightness = 2
|
||||||
self._button = PinHandler(watch.button)
|
self._button = PinHandler(watch.button)
|
||||||
|
|
||||||
|
@ -142,23 +145,40 @@ class Manager():
|
||||||
quick application ring. Applications on the ring are not permitted
|
quick application ring. Applications on the ring are not permitted
|
||||||
to subscribe to :py:data`EventMask.SWIPE_LEFTRIGHT` events.
|
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
|
:param int direction: The direction of the navigation
|
||||||
"""
|
"""
|
||||||
app_list = self.applications
|
app_list = self.applications
|
||||||
|
|
||||||
if direction == EventType.LEFT:
|
if direction == EventType.LEFT:
|
||||||
i = app_list.index(self.app) + 1
|
if self.app in app_list:
|
||||||
if i >= len(app_list):
|
i = app_list.index(self.app) + 1
|
||||||
|
if i >= len(app_list):
|
||||||
|
i = 0
|
||||||
|
else:
|
||||||
i = 0
|
i = 0
|
||||||
self.switch(app_list[i])
|
self.switch(app_list[i])
|
||||||
elif direction == EventType.RIGHT:
|
elif direction == EventType.RIGHT:
|
||||||
i = app_list.index(self.app) - 1
|
if self.app in app_list:
|
||||||
if i < 0:
|
i = app_list.index(self.app) - 1
|
||||||
i = len(app_list)-1
|
if i < 0:
|
||||||
|
i = len(app_list)-1
|
||||||
|
else:
|
||||||
|
i = 0
|
||||||
self.switch(app_list[i])
|
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:
|
elif direction == EventType.HOME:
|
||||||
i = app_list.index(self.app)
|
if self.app != app_list[0]:
|
||||||
if i != 0:
|
|
||||||
self.switch(app_list[0])
|
self.switch(app_list[0])
|
||||||
else:
|
else:
|
||||||
self.sleep()
|
self.sleep()
|
||||||
|
|
Loading…
Reference in New Issue