HPInc / HP-Digital-Microfluidics

HP Digital Microfluidics Software Platform and Libraries
MIT License
2 stars 0 forks source link

Add pause for user in macro language #219

Closed EvanKirshenbaum closed 5 months ago

EvanKirshenbaum commented 5 months ago

@cumbiem asked for the ability to put a pause for the user to do something and confirm. What he really wants is a dialog box or at least a button on the display, but that will take a bit of time to work out. What I can give him easily is the ability to optionally print a prompt and wait for the user to hit return.

What I'm thinking of is something along the lines of

pause for user;
wait for user("Hit return to continue");
d : to w's exit pad : prompt("Clear well", w's number, "and hit return") : enter well;

This should be pretty straightforward, except I need to make sure that the input() call happens in a separate thread. Also, I'm not sure what happens if multiple threads are waiting on input.

Thinking about this, it may just be easier to add the button. Sigh.

Migrated from internal repository. Originally created by @EvanKirshenbaum on Jan 15, 2023 at 4:39 PM PST. Closed on Jan 27, 2023 at 12:17 PM PST.
EvanKirshenbaum commented 5 months ago

This issue was referenced by the following commits before migration:

EvanKirshenbaum commented 5 months ago

It wasn't as hard as I thought to do (using an AsyncFunctionSerializer in BoardMonitor).

I also added an InjectableStatementType (and ...Value) below CallableType that indicates that the value should be invoked when the value of a statement (or interactive expression). I reimplemented pause and prompt using this, and it mostly works, but I need to figure out how to handle it correctly when it's the first element of the chain. If I say

prompt : pause 5 sec : prompt

I appear to get the pause first, then the initial prompt, then (immediately) the second prompt. But if I put the pauses between, say, two drop movements, everything works fine, even if there are multiple of them.

Migrated from internal repository. Originally created by @EvanKirshenbaum on Jan 17, 2023 at 2:56 PM PST.
EvanKirshenbaum commented 5 months ago

With the reworking of injections as part of #222, everything seems to work. (Printing is now an injectable statement/action, as well, so it can go in injection chains.)

The forms are

prompt
pause for user
wait for user

Each of these can optionally take one or more comma-separated arguments which will be displayed to the user. (I decided against the outside parentheses. This may be a mistake.)

The actual interaction is done via System.prompt_and_wait():

    def prompt_and_wait(self, future: Postable[None], *, prompt: Optional[str] = None) -> None:
        def doit() -> None:
            if prompt is not None:
                print(prompt)
            print("Hit <RETURN> to continue.")
            input()
            future.post(None)
        self.terminal_interaction.enqueue(doit)

where terminal_interaction is an AsyncFunctionSerializer. At some point, we may want to delegate to the BoardMonitor if there is one.

Migrated from internal repository. Originally created by @EvanKirshenbaum on Jan 27, 2023 at 12:17 PM PST.