diff --git a/res/knob.png b/res/knob.png new file mode 100644 index 0000000..579d26b Binary files /dev/null and b/res/knob.png differ diff --git a/wasp/apps/testapp.py b/wasp/apps/testapp.py index 6681aa5..43b99ca 100644 --- a/wasp/apps/testapp.py +++ b/wasp/apps/testapp.py @@ -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) diff --git a/wasp/icons.py b/wasp/icons.py index dec982a..ff39f8a 100644 --- a/wasp/icons.py +++ b/wasp/icons.py @@ -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' +) diff --git a/wasp/widgets.py b/wasp/widgets.py index 9271fe6..97410b0 100644 --- a/wasp/widgets.py +++ b/wasp/widgets.py @@ -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