Skip to content
This repository has been archived by the owner on Dec 23, 2021. It is now read-only.

Buttons Integration for clue #286

Merged
merged 16 commits into from
Apr 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/base_circuitpython/base_cp_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@

IMG_DIR_NAME = "img"
SCREEN_HEIGHT_WIDTH = 240

EXPECTED_INPUT_BUTTONS = ["button_a", "button_b"]
3 changes: 3 additions & 0 deletions src/base_circuitpython/displayio/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,6 @@ def __len__(self):
return 0
else:
return len(self.__contents)

def pop(self, i=-1):
return self.__contents.pop(i)
63 changes: 61 additions & 2 deletions src/clue/adafruit_clue.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,65 @@ class Clue: # pylint: disable=too-many-instance-attributes, too-many-public-met
RAINBOW = (RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE)

def __init__(self):
self._a = False
self._b = False
self.__pressed_buttons = set()
self._pixel = neopixel.NeoPixel(
pin=CONSTANTS.CLUE_PIN, n=1, pixel_order=neopixel.RGB
)

@property
def button_a(self):
"""``True`` when Button A is pressed. ``False`` if not.
This example prints when button A is pressed.
To use with the CLUE:
.. code-block:: python
from adafruit_clue import clue
while True:
if clue.button_a:
print("Button A pressed")
"""
return self._a

@property
def button_b(self):
"""``True`` when Button B is pressed. ``False`` if not.
This example prints when button B is pressed.
To use with the CLUE:
.. code-block:: python
from adafruit_clue import clue
while True:
if clue.button_b:
print("Button B pressed")
"""
return self._b

def __update_button(self, button, value):
if button == "button_a":
if value:
self.__pressed_buttons.add("A")
andreamah marked this conversation as resolved.
Show resolved Hide resolved
self._a = value
elif button == "button_b":
if value:
self.__pressed_buttons.add("B")
self._b = value

@property
def were_pressed(self):
"""Returns a set of the buttons that have been pressed.
To use with the CLUE:
.. code-block:: python
from adafruit_clue import clue
while True:
print(clue.were_pressed)
"""
ret = self.__pressed_buttons.copy()
andreamah marked this conversation as resolved.
Show resolved Hide resolved
self.__pressed_buttons.clear()
return ret

@property
def pixel(self):
"""The NeoPixel RGB LED.
.. image :: ../docs/_static/neopixel.jpg
:alt: NeoPixel
This example turns the NeoPixel purple.
To use with the CLUE:
.. code-block:: python
Expand Down Expand Up @@ -284,6 +334,15 @@ def simple_text_display(
colors=colors,
)

def update_state(self, new_state):
self.__update_buttons(new_state)

# helpers
def __update_buttons(self, new_state):
# get button pushes
for button_name in CONSTANTS.EXPECTED_INPUT_BUTTONS:
self.__update_button(button_name, new_state.get(button_name))


clue = Clue() # pylint: disable=invalid-name
"""Object that is automatically created on import.
Expand Down
17 changes: 17 additions & 0 deletions src/clue/test/test_adafruit_clue.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,20 @@ def test_clue_display_text(self):
clue_data.show()

helper._Helper__test_image_equality(displayio.bmp_img, expected)

def test_buttons(self):
BUTTON_A = "button_a"
BUTTON_B = "button_b"

clue._Clue__update_button(BUTTON_A, True)
assert clue.button_a
clue._Clue__update_button(BUTTON_A, False)
assert not clue.button_a

clue._Clue__update_button(BUTTON_B, True)
assert clue.button_b
clue._Clue__update_button(BUTTON_B, False)
assert not clue.button_b

assert set(["A", "B"]) == clue.were_pressed
assert set() == clue.were_pressed
29 changes: 29 additions & 0 deletions src/view/components/clue/Clue.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import { IntlProvider } from "react-intl";
import * as testRenderer from "react-test-renderer";
import { Clue } from "./Clue";

describe("Clue component", () => {
it("should render correctly", () => {
const component = testRenderer
.create(
<IntlProvider locale="en">
<Clue />
</IntlProvider>
)
.toJSON();
expect(component).toMatchSnapshot();
});

it("should render without crashing", () => {
const div = document.createElement("div");
ReactDOM.render(
<IntlProvider locale="en">
<Clue />
</IntlProvider>,
div
);
ReactDOM.unmountComponentAtNode(div);
});
});
1 change: 0 additions & 1 deletion src/view/components/clue/ClueImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import * as React from "react";
import { VIEW_STATE } from "../../constants";
import CONSTANTS, { BUTTON_STYLING_CLASSES } from "../../constants";
import { ViewStateContext } from "../../context";
import "../../styles/Microbit.css";
import { ClueSvg, IRefObject } from "./Clue_svg";

interface EventTriggers {
Expand Down
5 changes: 4 additions & 1 deletion src/view/components/clue/ClueSimulator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
// DEVICE_LIST_KEY,
CONSTANTS,
DEFAULT_IMG_CLUE,
DEVICE_LIST_KEY,
WEBVIEW_MESSAGES,
} from "../../constants";
import PlayLogo from "../../svgs/play_svg";
Expand Down Expand Up @@ -48,7 +49,9 @@ export class ClueSimulator extends React.Component<any, IState> {
}
handleMessage = (event: any): void => {
const message = event.data;

if (message.active_device !== DEVICE_LIST_KEY.CLUE) {
return;
}
switch (message.command) {
case "reset-state":
this.setState({
Expand Down
110 changes: 90 additions & 20 deletions src/view/components/clue/Clue_svg.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// Licensed under the MIT license.

import * as React from "react";
import CONSTANTS from "../../constants";
import "../../styles/Clue.css";
import "../../styles/SimulatorSvg.css";
import { DEFAULT_CLUE_STATE } from "./ClueSimulator";
import CONSTANTS from "../../constants";
export interface IRefObject {
[key: string]: React.RefObject<SVGRectElement>;
}
Expand Down Expand Up @@ -776,20 +776,76 @@ export class ClueSvg extends React.Component<IProps, {}> {
transform="translate(-49.27 -48.48)"
/>
</g>
<g id="Buttons">
<g
className="sim-button-group"
focusable="true"
tabIndex={0}
role="button"
aria-label="a"
ref={this.buttonRefs.BTN_A}
>
<rect
className="cls-10"
className="sim-button-outer"
x="13.19"
y="100.56"
width="35.04"
height="34.82"
rx="1.79"
/>
<circle
className="sim-button"
cx="30.71"
cy="117.86"
r="11.6"
/>
<circle
className="cls-14"
cx="17.49"
cy="104.88"
r="3.23"
/>
<circle
className="cls-14"
cx="43.92"
cy="104.88"
r="3.23"
/>
<circle
className="cls-14"
cx="43.92"
cy="131.03"
r="3.23"
/>
<circle
className="cls-14"
cx="17.49"
cy="131.03"
r="3.23"
/>
</g>
<g
className="sim-button-group"
focusable="true"
tabIndex={0}
role="button"
aria-label="b"
ref={this.buttonRefs.BTN_B}
>
<rect
className="sim-button-outer"
x="258.06"
y="100.27"
width="35.04"
height="34.82"
rx="1.79"
/>
<circle
className="cls-13"
className="sim-button"
focusable="false"
cx="275.58"
cy="117.58"
r="11.6"
style={{ strokeWidth: 0 }}
/>
<circle
className="cls-14"
Expand All @@ -815,45 +871,59 @@ export class ClueSvg extends React.Component<IProps, {}> {
cy="130.74"
r="3.23"
/>
</g>
<g
className="sim-button-group"
focusable="true"
tabIndex={0}
role="button"
aria-label="ab"
ref={this.buttonRefs.BTN_AB}
>
<rect
className="cls-15"
x="13.19"
y="100.56"
className="sim-button-outer"
x="327.48"
y="192.69"
width="35.04"
height="34.82"
rx="1.79"
/>
<circle
className="cls-13"
cx="30.71"
cy="117.86"
className="sim-button"
focusable="false"
cx="345"
cy="210"
r="11.6"
style={{ strokeWidth: 0 }}
/>
<circle
className="cls-14"
cx="17.49"
cy="104.88"
cx="331.79"
cy="197.02"
r="3.23"
/>
<circle
className="cls-14"
cx="43.92"
cy="104.88"
cx="358.21"
cy="197.02"
r="3.23"
/>
<circle
className="cls-14"
cx="43.92"
cy="131.03"
cx="358.21"
cy="223.16"
r="3.23"
/>
<circle
className="cls-14"
cx="17.49"
cy="131.03"
cx="331.79"
cy="223.16"
r="3.23"
/>
</g>
<text x={330} y={180} className="sim-text-outside-clue">
A+B
</text>
<g id="Buttons_at_top" data-name="Buttons at top">
<rect
className="cls-16"
Expand Down Expand Up @@ -961,7 +1031,7 @@ export class ClueSvg extends React.Component<IProps, {}> {
rx="18.28"
/>
</g>
<text x={318} y={85} className="sim-text-outside">
<text x={318} y={85} className="sim-text-outside-clue">
Neopixel
</text>
<circle cx={345} cy={115} r="30" fill="url(#grad1)" />
Expand Down
Loading