User interface

Terminal App

class dronemanager.app.StatusScreen(*args, **kwargs)

Bases: Screen

A screen showing detailed information for a single drone.

Initialize the screen.

Parameters:
  • name – The name of the screen.

  • id – The ID of the screen in the DOM.

  • classes – The CSS classes for the screen.

CSS = ' \nProgressBar {\n    width: 25;\n    height: 1;\n    layout: horizontal;\n}\n\nBar {\n    width: 20;\n    height: 1;\n}\n'

CSS for the status screen.

compose()

Creates the screen object

on_radio_set_changed(event: Changed) None
can_focus = False

Widget may receive focus.

can_focus_children = True

Widget’s children may receive focus.

class dronemanager.app.CommandScreen(*args, **kwargs)

Bases: Screen

Initialize the screen.

Parameters:
  • name – The name of the screen.

  • id – The ID of the screen in the DOM.

  • classes – The CSS classes for the screen.

STATUS_REFRESH_RATE = 20
CSS = '\n.text {\n    text-style: bold;\n}\n\n#status {\n    height: 10fr;\n}\n\n#usage {\n    height: 1fr;\n}\n\n#sidebar {\n    width: 97;\n}\n'

Inline CSS, useful for quick scripts. Rules here take priority over CSS_PATH.

Note

This CSS applies to the whole app.

dm: DroneManager
drone_widgets: dict[str, Widget]
running_tasks: set[asyncio.Task]
async cli(message)
async action_stop(names)
async exit()

Checks if any drones are armed and exits the app if not.

compose()

Creates the screen object

can_focus = False

Widget may receive focus.

can_focus_children = True

Widget’s children may receive focus.

class dronemanager.app.DroneApp(dm: DroneManager, logger=None)

Bases: App

Create an instance of an app.

Parameters:
  • driver_class – Driver class or None to auto-detect. This will be used by some Textual tools.

  • css_path – Path to CSS or None to use the CSS_PATH class variable. To load multiple CSS files, pass a list of strings or paths which will be loaded in order.

  • watch_css – Reload CSS if the files changed. This is set automatically if you are using textual run with the dev switch.

  • ansi_color – Allow ANSI colors if True, or convert ANSI colors to to RGB if False.

Raises:

CssPathError – When the supplied CSS path(s) are an unexpected type.

BINDINGS = {Binding(key='s', action='cycle_control', description='Swap Status/Control', show=True, key_display=None, priority=False, tooltip='', id=None, system=False)}

Key Bindings

TITLE = 'DroneManager'

Window Title

MODES = {'control': <class 'dronemanager.app.CommandScreen'>, 'status': <class 'dronemanager.app.StatusScreen'>}

A dictionary of the available app “modes”.

An app mode is essentially a different view, we can cycle between them. See the textual documentation for more information.

command_screen: CommandScreen | None
status_screen: StatusScreen | None
on_mount()
action_cycle_control()
dronemanager.app.check_cli_command_signatures(command: Callable) list[tuple]

Inspects a function signature to determine the type of the arguments, if they are optional, etc.

Returns a tuple for each argument. Each tuple contains:

  1. If the argument type hint is valid or not for our parsing.

  2. The name of the argument (i.e. “command” for this function.)

  3. If the argument expects a list.

  4. If the argument is required.

  5. If the argument accepts None.

  6. The base type of the argument, i.e. is a float or a string. For a list of floats, the base type is float.

  7. If the argument is keyword only.

  8. If the argument has a default value.

  9. The default value, or None if it doesn’t have one.

If a signature is invalid, the other fields may not be populated correctly or at all.

Parameters:

command – The function to be inspected.

Returns:

A list of tuples for each argument.

dronemanager.app.main()

Custom widgets

exception dronemanager.widgets.ArgumentParserError

Bases: Exception

exception dronemanager.widgets.PrintHelpInsteadOfParsingError

Bases: Exception

class dronemanager.widgets.ArgParser(*args, logger=None, **kwargs)

Bases: ArgumentParser

error(message: string)

Prints a usage message incorporating the message to stderr and exits.

If you override this in a subclass, it should not return – it should either exit or raise an exception.

print_help(file=None)
exit(status=0, message=None)
class dronemanager.widgets.InputWithHistory(*args, **kwargs)

Bases: Input

Initialise the Input widget.

Parameters:
  • value – An optional default value for the input.

  • placeholder – Optional placeholder text for the input.

  • highlighter – An optional highlighter for the input.

  • password – Flag to say if the field should obfuscate its content.

  • restrict – A regex to restrict character inputs.

  • type – The type of the input.

  • max_length – The maximum length of the input, or 0 for no maximum length.

  • suggester – [Suggester][textual.suggester.Suggester] associated with this input instance.

  • validators – An iterable of validators that the Input value will be checked against.

  • validate_on – Zero or more of the values “blur”, “changed”, and “submitted”, which determine when to do input validation. The default is to do validation for all messages.

  • valid_empty – Empty values are valid.

  • select_on_focus – Whether to select all text on focus.

  • name – Optional name for the input widget.

  • id – Optional ID for the widget.

  • classes – Optional initial classes for the widget.

  • disabled – Whether the input is disabled or not.

  • tooltip – Optional tooltip.

BINDINGS = [Binding(key='left', action='cursor_left', description='Move cursor left', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='shift+left', action='cursor_left(True)', description='Move cursor left and select', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+left', action='cursor_left_word', description='Move cursor left a word', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+shift+left', action='cursor_left_word(True)', description='Move cursor left a word and select', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='right', action='cursor_right', description='Move cursor right or accept the completion suggestion', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='shift+right', action='cursor_right(True)', description='Move cursor right and select', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+right', action='cursor_right_word', description='Move cursor right a word', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+shift+right', action='cursor_right_word(True)', description='Move cursor right a word and select', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='backspace', action='delete_left', description='Delete character left', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='home,ctrl+a', action='home', description='Go to start', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='end,ctrl+e', action='end', description='Go to end', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='shift+home', action='home(True)', description='Select line start', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='shift+end', action='end(True)', description='Select line end', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='delete,ctrl+d', action='delete_right', description='Delete character right', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='enter', action='submit', description='Submit', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+w', action='delete_left_word', description='Delete left to start of word', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+u', action='delete_left_all', description='Delete all to the left', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+f', action='delete_right_word', description='Delete right to start of word', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+k', action='delete_right_all', description='Delete all to the right', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+x', action='cut', description='Cut selected text', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+c', action='copy', description='Copy selected text', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='ctrl+v', action='paste', description='Paste text from the clipboard', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='up', action='history_prev', description='Previous item from history', show=False, key_display=None, priority=False, tooltip='', id=None, system=False), Binding(key='down', action='history_rec', description='Next item in history', show=False, key_display=None, priority=False, tooltip='', id=None, system=False)]
Key(s) | Description |
:- | :- |
left | Move the cursor left. |
shift+left | Move cursor left and select. |
ctrl+left | Move the cursor one word to the left. |
right | Move the cursor right or accept the completion suggestion. |
ctrl+shift+left | Move cursor left a word and select. |
shift+right | Move cursor right and select. |
ctrl+right | Move the cursor one word to the right. |
backspace | Delete the character to the left of the cursor. |
ctrl+shift+right | Move cursor right a word and select. |
home,ctrl+a | Go to the beginning of the input. |
end,ctrl+e | Go to the end of the input. |
shift+home | Select up to the input start. |
shift+end | Select up to the input end. |
delete,ctrl+d | Delete the character to the right of the cursor. |
enter | Submit the current value of the input. |
ctrl+w | Delete the word to the left of the cursor. |
ctrl+u | Delete everything to the left of the cursor. |
ctrl+f | Delete the word to the right of the cursor. |
ctrl+k | Delete everything to the right of the cursor. |
ctrl+x | Cut selected text. |
ctrl+c | Copy selected text. |
ctrl+v | Paste text from the clipboard. |
action_history_prev() None
action_history_rec() None
add_to_history(item) None
async action_submit() None

Handle a submit action.

Normally triggered by the user pressing Enter. This may also run any validators.

can_focus = True

Widget may receive focus.

can_focus_children = True

Widget’s children may receive focus.

class dronemanager.widgets.DroneOverview(drone, update_frequency, logger, *args, **kwargs)

Bases: Static

Initialize a Widget.

Parameters:
  • *children – Child widgets.

  • name – The name of the widget.

  • id – The ID of the widget in the DOM.

  • classes – The CSS classes for the widget.

  • disabled – Whether the widget is disabled or not.

COLUMN_NAMES = ['Name', 'Status', 'Modes', 'GPS', 'Local', 'Vel', 'Yaw/Bat']
COLUMN_WIDTHS = [10, 11, 11, 16, 9, 9, 8]
COLUMN_ALIGN = ['<', '>', '>', '>', '>', '>', '>']
COLUMN_SPACING = 3
classmethod header_string()
classmethod gadget_width()
on_mount() None
async update_display()
can_focus = False

Widget may receive focus.

can_focus_children = True

Widget’s children may receive focus.

class dronemanager.widgets.TextualLogHandler(log_textual, *args, **kwargs)

Bases: Handler

Initializes the instance - basically setting the formatter to None and the filter list to empty.

log_textual: Log
emit(record)

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.