Skip to content

Interacting with users in Bliss

Programming interactions with users can be simplified by using Bliss dialogs or getval_XXX functions.

To know more about dialogs API, see: Dialogs

To know more about the menu command, see: Show

The following document will define the recomended way to integrate dialogs inside Bliss.

Bliss dialogs

User Interface to dialogs

The users will access dialogs using the menu function available in the Bliss shell exported from bliss.shell.standard.

Programmer interface to dialogs

This paragraph is about how to add your own dialogs to bliss or beamline repository interacting with the menu() function.

What you have to do is simply define your function that takes as first argument the object instance itself (on which you will operate) and decorate it with @dialog("MyClassName", "dialog_type").

This will register the dialog as available for this specific object or class of objects.

If you try to register the same Class twice you wil get an exception, but you can force this with @dialog("MyClassName", "dialog_type", overwrite=True). This is to avoid unexpected behavior when you register twice the same name.

Full Example:

from bliss.shell.dialog.helpers import dialog
from bliss.shell.cli.user_dialog import UserCheckBox
from bliss.shell.cli.pt_widgets import BlissDialog
from bliss.common.utils import grouped_with_tail


@dialog("Transfocator", "selection")
def transfocator_menu(obj, *args, **kwargs):
    """Transfocator Pinhole/Lens selection"""
    dialogs = []
    positions_list = obj.status_dict()
    for label, position in positions_list.items():
        type_ = "Pinhole" if label.startswith("P") else "Lens"
        num = label[1:]
        dialogs.append(UserCheckBox(label=f"{type_} n.{num}", defval=position))

    layout = []

    for gr in grouped_with_tail(dialogs, 6):
        layout.append(gr)

    choices = BlissDialog(
        layout,
        title="Transfocator selection (checked is IN, unchecked is OUT)",
        paddings=(3, 0),
    ).show()
    if choices:
        for n, position in enumerate(choices.values()):
            obj[n] = position
    return obj
  • @dialog("Transfocator", "selection"): import this decorator from bliss.shell.dialog.helpers and decorate your function with the Class Name and dialog type.

  • obj: this is the first argument received from menu.

  • *args, **kwargs: further args received from menu(obj, dialog_type, *args, **kwargs)

  • return obj: is not compulsory to return something. In some case is good to return obj because many bliss objects has implemented the __info__ method that will display a status on Bliss shell. In some other cases could be too verbose or simply not necessary. The idea is to return something that will display the result of your dialog operation. If you want to return and print something on the shell is recomended to simply use ShellStr from bliss.common.utils.

Plenty of examples can be found inside the bliss/shell/dialogs folder.

Note

Be aware that the dialog code should be imported to work.

For the bliss package this is normally done inside bliss/shell/dialog/__init__.py.

getval functions

  • getval_yes_no:
  • getval_name:
  • getval_int_range:
  • getval_idx_list:
  • getval_char_list:

getval_ functions are a set of functions to prompt user to enter interactively various types of inputs: int, float, string, yes/no answer to a question etc.

getval_yes_no

getval_yes_no(message, default=True)

from bliss.shell.getval import getval_yes_no

if getval_yes_no("Do you want to open shutter ?", default="no"):
    print("ok, openning...")
else:
    print("abort...")

User is prevented to type other input than yes or no or y or n.

Executions example:

Do you want to open shutter ? [y/N]: bof
The input have to be on of [y]es or [n]o

On Enter:

Do you want to open shutter ? [y/N]:
abort...

On Ctrl-C:

Do you want to open shutter ? [y/N]:
!!! === KeyboardInterrupt:  === !!! ( for more details type cmd 'last_error()' )

Do you want to open shutter ? [y/N]: y
ok, openning...

getval_name

getval_name prompt for a string without special char or spaces.

DEMO [8]: getval.getval_name("Enter a valid name")
Enter a valid name : fdsf

getval_int_range

getval_int_range(message, minimum, maximum, default): Prompt user for an int number in interval [min, max]

from bliss.shell.getval import getval_int_range
getval_int_range("Please enter beamline number", minimum=1, maximum=32, default=1)
execution:
Please enter beamline number [1]: f
Error: f is not a valid integer
Please enter beamline number [1]: 99
Error: 99 is not in the valid range of 1 to 32.
Please enter beamline number [1]: 5
Out[2]: 5

getval_idx_list

getval_idx_list(): Return the index and string chosen by user in list of N strings. Selection is done by index in [1..N].

Example:

from bliss.shell.getval import getval_idx_list

dspacing_list = ["111", "311", "642"]
print(getval_idx_list(dspacing_list,"Choose the index of dspacing you want to use"))

Execution of previous example:

1 - 111
2 - 311
3 - 642
Choose the index of dspacing you want to use [1]: 2
311

getval_char_list

from bliss.shell.getval import getval_char_list

actions_list= [("a", "add a roi"), ("r", "remove a roi"), ("m", "modify a roi")]
getval_char_list(actions_list, "Action to do")

Execution of previous example:

a - add a roi
r - remove a roi
m - modify a roi
Action to do (a, r, m):a
  Out [11]: ('a', 'add a roi')