import * as React from "react" ; import { BUTTON_CLASSNAME , VIEW_STATE } from "../../constants" ; import CONSTANTS , { BUTTON_STYLING_CLASSES } from "../../constants" ; import { ViewStateContext } from "../../context" ; import { IRefObject , MicrobitSvg } from "./Microbit_svg" ; interface EventTriggers { onMouseUp : ( event : Event , buttonKey : string ) => void ; onMouseDown : ( event : Event , buttonKey : string ) => void ; onKeyEvent : ( event : KeyboardEvent , active : boolean , key : string ) => void ; } interface IProps { eventTriggers : EventTriggers ; leds : number [ ] [ ] ; } export enum BUTTONS_KEYS { BTN_A = "BTN_A" , BTN_B = "BTN_B" , BTN_AB = "BTN_AB" } export class MicrobitImage extends React . Component < IProps , { } > { private svgRef : React . RefObject < MicrobitSvg > = React . createRef ( ) ; constructor ( props ) { super ( props ) ; } componentDidMount ( ) { const svgElement = this . svgRef . current ; if ( svgElement ) { updateAllLeds ( this . props . leds , svgElement . getLeds ( ) ) ; setupAllButtons ( this . props . eventTriggers , svgElement . getButtons ( ) ) ; this . setupKeyPresses ( this . props . eventTriggers . onKeyEvent ) ; } } componentDidUpdate ( ) { if ( this . svgRef . current ) { updateAllLeds ( this . props . leds , this . svgRef . current . getLeds ( ) ) ; if ( this . context === VIEW_STATE . PAUSE ) { disableAllButtons ( this . svgRef . current . getButtons ( ) ) ; } else if ( this . context === VIEW_STATE . RUNNING ) { setupAllButtons ( this . props . eventTriggers , this . svgRef . current . getButtons ( ) ) ; } } } componentWillUnmount ( ) { window . document . removeEventListener ( "keydown" , this . handleKeyDown ) ; window . document . removeEventListener ( "keyup" , this . handleKeyUp ) ; } setupKeyPresses = ( onKeyEvent ) => { window . document . addEventListener ( "keydown" , this . handleKeyDown ) ; window . document . addEventListener ( "keyup" , this . handleKeyUp ) ; } ; handleKeyDown = ( event ) => { const keyEvents = [ event . key , event . code ] ; if ( ! ( keyEvents . includes ( CONSTANTS . KEYBOARD_KEYS . CAPITAL_F ) || keyEvents . includes ( CONSTANTS . KEYBOARD_KEYS . CAPITAL_R ) || keyEvents . includes ( CONSTANTS . KEYBOARD_KEYS . ENTER ) ) ) { this . props . eventTriggers . onKeyEvent ( event , true , event . key ) ; } } ; handleKeyUp = ( event ) => { this . props . eventTriggers . onKeyEvent ( event , false , event . key ) ; } ; render ( ) { return < MicrobitSvg ref = { this . svgRef } />; } public updateButtonAttributes ( key , isActive ) { const button = this . svgRef . current ?. getButtons ( ) [ key ] . current ; if ( button ) { button . focus ( ) ; if ( isActive ) { button . children [ 0 ] . setAttribute ( "class" , BUTTON_STYLING_CLASSES . KEYPRESSED ) ; } else { button . children [ 0 ] . setAttribute ( "class" , BUTTON_STYLING_CLASSES . DEFAULT ) ; } button . setAttribute ( "pressed" , `${ isActive }` ) ; button . setAttribute ( "aria-pressed" , `${ isActive }` ) ; } } } MicrobitImage . contextType = ViewStateContext ; const setupButton = ( buttonElement , eventTriggers , key ) => { buttonElement . setAttribute ( "class" , BUTTON_CLASSNAME . ACTIVE ) ; buttonElement . onmousedown = e => { buttonElement . focus ( ) ; eventTriggers . onMouseDown ( e , key ) ; } ; buttonElement . onmouseup = e => { eventTriggers . onMouseUp ( e , key ) ; } ; buttonElement . onkeydown = e => { if ( e . key === CONSTANTS . KEYBOARD_KEYS . ENTER ) { eventTriggers . onKeyEvent ( e , true , key ) ; } } ; buttonElement . onkeyup = e => { eventTriggers . onKeyEvent ( e , false , key ) ; } ; } ; const setupAllButtons = ( eventTriggers , buttonRefs ) => { for ( const [ key , ref ] of Object . entries ( buttonRefs ) ) { if ( ref . current ) { setupButton ( ref . current , eventTriggers , key ) ; } } } ; const disableAllButtons = ( buttonRefs ) => { for ( const [ , ref ] of Object . entries ( buttonRefs ) ) { if ( ref . current ) { ref . current . onmousedown = null ; ref . current . onmouseup = null ; ref . current . onkeydown = null ; ref . current . onkeyup = null ; ref . current . setAttribute ( "class" , BUTTON_CLASSNAME . DEACTIVATED ) ; } } } ; const updateAllLeds = ( leds , ledRefs ) => { for ( let j = 0 ; j < leds . length ; j ++ ) { for ( let i = 0 ; i < leds [ 0 ] . length ; i ++ ) { const ledElement = ledRefs [ j ] [ i ] . current ; if ( ledElement ) { setupLed ( ledElement , leds [ i ] [ j ] ) ; } } } } ; const setupLed = ( ledElement , brightness ) => { ledElement . style . opacity = ( brightness / 10 ) . toString ( ) ; } ;