Module ui.trapper

Trapper module: provides methods for simple interaction with UI, without the need for explicit callbacks, for use by linear jobs between their steps.

Allows code to trap UI (give progress info to UI, ask for user choice), or get trapped by UI (get interrupted). Mostly done with coroutines, but hides their usage for simplicity.

Functions

Trapper:wrap (func) Executes a function and allows it to be trapped (that is: to use our other methods).
Trapper:isWrapped () Returns if code is wrapped
Trapper:clear () Clears left-over widget
Trapper:reset () Clears left-over widget and resets Trapper state
Trapper:info (text) Displays an InfoMessage, and catches dismissal.
Trapper:setPausedText (text, abort_text, continue_text) Overrides text and button texts on the Paused ConfirmBox.
Trapper:confirm (text, cancel_text, ok_text) Displays a ConfirmBox and gets user's choice.
Trapper:dismissablePopen (cmd, trap_widget_or_string) Dismissable wrapper for io.popen(cmd).
Trapper:dismissableRunInSubprocess (task, trap_widget_or_string) Run a function (task) in a sub-process, allowing it to be dismissed, and returns its return value(s).


Functions

Trapper:wrap (func)
Executes a function and allows it to be trapped (that is: to use our other methods).

Simple wrapper function for a coroutine, which is a prerequisite for all our methods (this simply abstracts the coroutine business to our callers), and execute it.

(If some code is not wrap()'ed, most of the other methods, when called, will simply log or fallback to a non-UI action or OK choice.)

This call should be the last step in some event processing code, as it may return early (the first coroutine.yield() in any of the other methods will return from this function), and later be resumed by UIManager. So any following (unwrapped) code would be then executed while func is half-done, with unintended consequences.

Parameters:

  • func function reference to function to wrap and execute
Trapper:isWrapped ()
Returns if code is wrapped

Returns:

    boolean true if code is wrapped by Trapper, false otherwise
Trapper:clear ()
Clears left-over widget
Trapper:reset ()
Clears left-over widget and resets Trapper state
Trapper:info (text)
Displays an InfoMessage, and catches dismissal.

Display a InfoMessage with text, or keep existing InfoMessage if text = nil, and return true.

UNLESS the previous widget was itself a InfoMessage and it has been dismissed (by Tap on the screen), in which case the new InfoMessage is not displayed, and false is returned.

One can only know a InfoMessage has been dismissed when trying to display a new one (we can't do better than that with coroutines). So, don't hesitate to call it regularly (each call costs 100ms), between steps of the work, to provide good responsiveness.

Trapper:info() is a shortcut to get dismiss info while keeping the existing InfoMessage displayed.

Optional fast_refresh parameter should only be used when displaying an InfoMessage over a previous InfoMessage of the exact same size.

Parameters:

  • text string text to display as an InfoMessage (or nil to keep existing one)

Returns:

    boolean true if InfoMessage was not dismissed, false if dismissed

Usage:

    Trapper:info("some text about step or progress")
    go_on = Trapper:info()
Trapper:setPausedText (text, abort_text, continue_text)
Overrides text and button texts on the Paused ConfirmBox.

A ConfirmBox is displayed when an InfoMessage is dismissed in Trapper:info(), with default text "Paused", and default buttons "Abort" and "Continue".

Parameters:

  • text string ConfirmBox text (default: "Paused")
  • abort_text string ConfirmBox "Abort" button text (Trapper:info() returns false)
  • continue_text string ConfirmBox "Continue" button text
Trapper:confirm (text, cancel_text, ok_text)
Displays a ConfirmBox and gets user's choice.

Display a ConfirmBox with the text and canceltext/oktext buttons, block and wait for user's choice, and return the choice made: false if Cancel tapped or dismissed, true if OK tapped

Parameters:

  • text string text to display in a ConfirmBox
  • cancel_text string text for ConfirmBox Cancel button
  • ok_text string text for ConfirmBox Ok button

Returns:

    boolean false if Cancel tapped or dismissed, true if OK tapped

Usage:

    go_on = Trapper:confirm("Do you want to go on?")
    that_selected = Trapper:confirm("Do you want to do this or that?", "this", "that"))
Trapper:dismissablePopen (cmd, trap_widget_or_string)
Dismissable wrapper for io.popen(cmd).

Notes and limitations:

1) It is dismissable as long as cmd as not yet output anything. Once output has started, the reading will block till it is done. (Some shell tricks, included in cmd, could probably be used to accumulate cmd output in some variable, and to output the whole variable to stdout at the end.)

2) cmd needs to output something (we will wait till some data is available) If there are chances for it to not output anything, append "; echo" to cmd

3) We need a TrapWidget or InfoMessage, that, as a modal, will catch any Tap event happening during cmd execution. This can be an existing already displayed widget, or provided as a string (a new TrapWidget will be created). If nil, true or false, an invisible TrapWidget will be used instead (if nil or true, the event will be resent; if false, the event will not be resent).

If we really need to have more control, we would need to use select() via ffi or do low level non-blocking reading on the file descriptor. If there are cmd that may not exit, that we would be trying to collect indefinitely, the best option would be to compile any timeout.c and use it as a wrapper.

Parameters:

  • cmd string shell cmd to execute and get output from
  • trap_widget_or_string already shown widget, string, or nil, true or false

Returns:

  1. boolean completed (true if not interrupted, false if dismissed)
  2. string output of command
Trapper:dismissableRunInSubprocess (task, trap_widget_or_string)
Run a function (task) in a sub-process, allowing it to be dismissed, and returns its return value(s).

Notes and limitations:

1) As function is run in a sub-process, it can't modify the main KOReader process (its parent). It has access to the state of KOReader at the time the sub-process was started. It should not use any service/driver that would make the parent process vision of the device state incoherent (ie: it should not use UIManager, display widgets, change settings, enable wifi...). It is allowed to modify the filesystem, as long as KOreader has not a cached vision of this filesystem part. Its returned value(s) are returned to the parent.

2) task may return complex data structures (but with simple lua types, no function) or a single string. If task returns a string or nil, set taskreturnssimple_string to true, allowing for some optimisations to be made.

3) If dismissed, the sub-process is killed with SIGKILL, and task is aborted without any chance for cleanup work: use of temporary files should so be limited (do some cleanup of dirty files from previous aborted executions at the start of each new execution if needed), and try to keep important operations as atomic as possible.

4) We need a TrapWidget or InfoMessage, that, as a modal, will catch any Tap event happening during cmd execution. This can be an existing already displayed widget, or provided as a string (a new TrapWidget will be created). If nil, true or false, an invisible TrapWidget will be used instead (if nil or true, the event will be resent; if false, the event will not be resent).

Parameters:

  • task lua function to execute and get return values from
  • trap_widget_or_string already shown widget, string, or nil, true or false

Returns:

  1. boolean completed (true if not interrupted, false if dismissed)
  2. ... return values of task
generated by LDoc 1.5.0 Last updated 2024-03-18 16:45:36