widgets: Introduce a slider widget

Currently the slider doesn't actually slide (because we process touch
events rather than swipe events) but we've called is a slider anyway.
This commit is contained in:
Daniel Thompson 2020-05-24 14:20:02 +01:00
parent 57999226fd
commit de647b324c
4 changed files with 118 additions and 3 deletions

BIN
res/knob.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -16,10 +16,16 @@ class TestApp():
ICON = icons.app
def __init__(self):
self.tests = ('Button', 'Crash', 'RLE', 'String', 'Touch', 'Wrap')
self.tests = ('Button', 'Crash', 'Colours', 'RLE', 'String', 'Touch', 'Wrap')
self.test = self.tests[0]
self.scroll = wasp.widgets.ScrollIndicator()
self._sliders = (
wasp.widgets.Slider(32, 10, 90, 0xf800),
wasp.widgets.Slider(64, 10, 140, 0x27e4),
wasp.widgets.Slider(32, 10, 190, 0x211f),
)
def foreground(self):
"""Activate the application."""
self.on_screen = ( -1, -1, -1, -1, -1, -1 )
@ -55,7 +61,14 @@ class TestApp():
self._draw()
def touch(self, event):
if self.test == 'RLE':
if self.test == 'Colours':
if event[2] > 90:
s = self._sliders[(event[2] - 90) // 50]
s.touch(event)
s.update()
self.scroll.draw()
self._update_colours()
elif self.test == 'RLE':
self._benchmark_rle()
elif self.test == 'String':
self._benchmark_string()
@ -119,12 +132,26 @@ class TestApp():
draw.fill()
draw.string('{} test'.format(self.test),
0, 6, width=240)
self.scroll.draw()
if self.test == 'Crash':
draw.string("Press button to", 12, 24+24)
draw.string("throw exception.", 12, 24+48)
elif self.test == 'Colours':
for s in self._sliders:
s.draw()
self._update_colours()
elif self.test == 'RLE':
draw.blit(self.ICON, 120-48, 120-32)
self.scroll.draw()
wasp.watch.display.mute(False)
def _update_colours(self):
draw = wasp.watch.drawable
r = self._sliders[0].value
g = self._sliders[1].value
b = self._sliders[2].value
rgb = (r << 11) + (g << 5) + b
draw.string('RGB565 #{:04x}'.format(rgb), 0, 6, width=240)
draw.fill(rgb, 60, 35, 120, 50)

View File

@ -139,3 +139,14 @@ up_arrow = (16, 9, b'\x07\x02\r\x04\x0b\x06\t\x08\x07\n\x05\x0c\x03\x0e\x01 ')
# 1-bit RLE, generated from res/down_arrow.png, 17 bytes
down_arrow = (16, 9, b'\x00 \x01\x0e\x03\x0c\x05\n\x07\x08\t\x06\x0b\x04\r\x02\x07')
# 2-bit RLE, generated from res/knob.png, 72 bytes
knob = (
b'\x02'
b'(('
b'\x10\xc8\x1c\xd0\x16\xd4\x13\xd6\x10\xda\r\xdc\x0b\xde\t\xe0'
b'\x08\xe0\x07\xe2\x05\xe4\x04\xe4\x03\xe6\x02\xe6\x02\xe6\x02\xe6'
b'\x01\xff\xff\x02\x01\xe6\x02\xe6\x02\xe6\x02\xe6\x03\xe4\x04\xe4'
b'\x05\xe2\x07\xe0\x08\xe0\t\xde\x0b\xdc\r\xda\x10\xd6\x13\xd4'
b'\x16\xd0\x1c\xc8\x10'
)

View File

@ -10,6 +10,7 @@ shared between applications.
import icons
import watch
from micropython import const
class BatteryMeter(object):
"""Battery meter widget.
@ -94,3 +95,79 @@ class ScrollIndicator():
draw.rleblit(icons.up_arrow, pos=self._pos, fg=0x7bef)
if self.down:
draw.rleblit(icons.down_arrow, pos=(self._pos[0], self._pos[1] + 13), fg=0x7bef)
_SLIDER_KNOB_DIAMETER = const(40)
_SLIDER_KNOB_RADIUS = const(_SLIDER_KNOB_DIAMETER // 2)
_SLIDER_WIDTH = const(220)
_SLIDER_TRACK = const(_SLIDER_WIDTH - _SLIDER_KNOB_DIAMETER)
_SLIDER_TRACK_HEIGHT = const(8)
_SLIDER_TRACK_Y1 = const(_SLIDER_KNOB_RADIUS - (_SLIDER_TRACK_HEIGHT // 2))
_SLIDER_TRACK_Y2 = const(_SLIDER_TRACK_Y1 + _SLIDER_TRACK_HEIGHT)
class Slider():
"""A slider to select values."""
def __init__(self, steps, x=10, y=90, color=0x39ff):
self.value = 0
self._steps = steps
self._stepsize = _SLIDER_TRACK / (steps-1)
self._x = x
self._y = y
self._color = color
# Automatically generate a lowlight color
if color < 0b10110_000000_00000:
color = (color | 0b10110_000000_00000) & 0b10110_111111_11111
if (color & 0b111111_00000) < 0b101100_00000:
color = (color | 0b101100_00000) & 0b11111_101100_11111
if (color & 0b11111) < 0b10110:
color = (color | 0b11000) & 0b11111_111111_10110
self._lowlight = color
def draw(self):
"""Draw the slider."""
draw = watch.drawable
x = self._x
y = self._y
color = self._color
light = self._lowlight
knob_x = x + ((_SLIDER_TRACK * self.value) // (self._steps-1))
draw.blit(icons.knob2, knob_x, y, color)
w = knob_x - x
if w > 0:
draw.fill(0, x, y, w, _SLIDER_TRACK_Y1)
if w > _SLIDER_KNOB_RADIUS:
draw.fill(0, x, y+_SLIDER_TRACK_Y1,
_SLIDER_KNOB_RADIUS, _SLIDER_TRACK_HEIGHT)
draw.fill(color, x+_SLIDER_KNOB_RADIUS, y+_SLIDER_TRACK_Y1,
w-_SLIDER_KNOB_RADIUS, _SLIDER_TRACK_HEIGHT)
else:
draw.fill(0, x, y+_SLIDER_TRACK_Y1, w, _SLIDER_TRACK_HEIGHT)
draw.fill(0, x, y+_SLIDER_TRACK_Y2, w, _SLIDER_TRACK_Y1)
sx = knob_x + _SLIDER_KNOB_DIAMETER
w = _SLIDER_WIDTH - _SLIDER_KNOB_DIAMETER - w
if w > 0:
draw.fill(0, sx, y, w, _SLIDER_TRACK_Y1)
if w > _SLIDER_KNOB_RADIUS:
draw.fill(0, sx+w-_SLIDER_KNOB_RADIUS, y+_SLIDER_TRACK_Y1,
_SLIDER_KNOB_RADIUS, _SLIDER_TRACK_HEIGHT)
draw.fill(light, sx, y+_SLIDER_TRACK_Y1,
w-_SLIDER_KNOB_RADIUS, _SLIDER_TRACK_HEIGHT)
else:
draw.fill(0, sx, y+_SLIDER_TRACK_Y1, w, _SLIDER_TRACK_HEIGHT)
draw.fill(0, sx, y+_SLIDER_TRACK_Y2, w, _SLIDER_TRACK_Y1)
def update(self):
self.draw()
def touch(self, event):
tx = event[1]
threshold = self._x + 20 - (self._stepsize / 2)
v = int((tx - threshold) / self._stepsize)
if v < 0:
v = 0
elif v >= self._steps:
v = self._steps - 1
self.value = v