microbit-foundation / micropython-microbit-v2

Temporary home for MicroPython for micro:bit v2 as we stablise it before pushing upstream
MIT License
42 stars 23 forks source link

Add Logo pressed / touched / released events #7

Open microbit-giles opened 3 years ago

microbit-giles commented 3 years ago

Following discussions arising from building the first sets of projects for the website, MakeCode now has 4 events associated with the logo:

I'm building a timer project for in-market launch that times how long you keep your finger on the logo, like this: microbit-screenshot (31)

Can we have the following to match the behaviours in MakeCode?

dpgeorge commented 3 years ago

It seems like these would also make sense on existing buttons, and also touch pins. Would they be added to all button-like objects for consistency?

pin_logo.is_pressed() - works like a button push, triggered on release

This method already exists for buttons and has semantics of "return true if it is currently being pressed". It would be confusing if the same method name had different semantics on the logo. And was_pressed() is triggered on push (not release). So the method might need to be called was_released().

pin_logo.is_touched() - triggered when you first touch the logo

This has semantics the same as is_pressed(): "return true if it is currently being touched". Ie it's not edge triggered but level triggered.

pin_logo.is_released() - triggered when you stop touching the logo

This might need to be was_released() to match was_pressed().

pin_logo.is_long_pressed()

Is this a continuous event (returns true so long as it continues to be touched) or one-off (returns true only once for the whole long press)?

microbit-giles commented 3 years ago

Good questions! Re. consistency with physical buttons, I need to think about that - @jaustin @microbit-carlos any thoughts on this and the more general point about naming?

Is this [long_pressed] a continuous event?

In MakeCode this event triggers once when you let go.

jaustin commented 3 years ago

Okay, part of the issue with doing this is that the 'pressed' in MicroPython is different to 'pressed' in MakeCode

Pressed in MicroPython is equivalent to the MakeCode 'touched' feature of the logo, in that it's true while the button is held down.

Sort of weirdly "was_pressed" is more like "pressed"

Here's a very quick loop that breaks out the states that I think you're looking for Giles. I think to decide if we want something more in MicroPython we should first refactor this to the simplest implementation and then see if adding anything else in the API would make it easier.

Off the top of my head, a was_pressed and was_long_pressed for both the buttons and the logo could make this script simpler.

from microbit import *

touched = 0

def a_pressed():
    display.show(Image.ARROW_W)
    sleep(500)

def logo_touched():
    display.show(Image.ARROW_N)
    sleep(500)

def logo_released():
    display.show(Image.ARROW_S)
    sleep(500)

def logo_pressed():
    display.show(Image.DIAMOND_SMALL)
    sleep(500)

def logo_long_pressed():
    display.show(Image.DIAMOND)
    sleep(500)

while True:
    if button_a.is_pressed():
        a_pressed()
    elif pin_logo.is_touched():
        touched = touched + 1
        logo_touched()
    else:
        if touched != 0:
            logo_released()
            if touched > 2:
                logo_long_pressed()
            else:
                logo_pressed()
            touched = 0
        display.show(Image.SQUARE_SMALL)

display.clear()
jaustin commented 3 years ago

...on further reflection, I think it's the state tracking that makes this unintuitive for a beginner programmer. At least my experience with block-based coding is that it's hard to teach variables as they're quite abstract, so getting as much achieved as possible before that is useful, as you've got more concrete understanding of logic to build from.

This doesn't get rid of a local variable but does do a bit less with it, though it also uses "while/else" which I think might end up also being confusing

# Add your Python code here. E.g.
from microbit import *
import utime

touched = 0

def a_pressed():
    display.show(Image.ARROW_W)
    sleep(500)

def logo_touched():
    display.show(Image.ARROW_N)
    sleep(500)

def logo_released():
    display.show(Image.ARROW_S)
    sleep(500)

def logo_pressed():
    display.show(Image.DIAMOND_SMALL)
    sleep(500)

def logo_long_pressed():
    display.show(Image.DIAMOND)
    sleep(500)

while True:
    if button_a.is_pressed():
        a_pressed()

    if pin_logo.is_touched():
        start_time = utime.ticks_ms()
        while pin_logo.is_touched():
            logo_touched()
        else:
            logo_released()
            print(utime.ticks_diff(utime.ticks_ms(), start_time))
            if utime.ticks_diff(utime.ticks_ms(), start_time) < 2000:
                logo_pressed()
            else:
                logo_long_pressed()

    display.show(Image.SQUARE_SMALL)

display.clear()
microbit-giles commented 3 years ago

If I've understood correctly that this second program is for users to implement for the desired functionality, I think it's too complex, especially when MakeCode has a single block for each case. Happy to have a call to discuss.

jaustin commented 3 years ago

@microbit-giles you have understood it correctly, yes, so I think we should spec out what kind of events we'd want to expose. I suspect it also means implementing them in V1 MicroPython? Or do you think having them just on the logo touch is acceptable here?

microbit-giles commented 3 years ago

I think it would be okay to have them just on the logo touch, but I can see a case for implementing them more widely in V1 MicroPython. @microbit-carlos any thoughts?

microbit-mark commented 3 years ago

It would be great to have this for the touch logo, to maintain parity with the API in MakeCode. Is it easier to decouple this from implementing it across all touch pins/buttons and return to that later?

The touch pin API partity was also requested in https://support.microbit.org/a/tickets/46668 (private) from a teacher who has students working in MakeCode Blocks, MakeCode Python and MicroPython.