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:
parent
57999226fd
commit
de647b324c
4 changed files with 118 additions and 3 deletions
BIN
res/knob.png
Normal file
BIN
res/knob.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4 KiB |
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue