sovabids.tui ============ .. py:module:: sovabids.tui .. autoapi-nested-parse:: Terminal User Interface for sovabids. Classes ------- .. autoapisummary:: sovabids.tui.DirPickerScreen sovabids.tui.SetupPane sovabids.tui.FilesListScreen sovabids.tui.ChannelNamesScreen sovabids.tui.RulesPane sovabids.tui.MappingsPane sovabids.tui.ConvertPane sovabids.tui.SovabidsApp Functions --------- .. autoapisummary:: sovabids.tui._flatten_dict sovabids.tui.main Module Contents --------------- .. py:class:: DirPickerScreen(start: str = '.') Bases: :py:obj:`textual.screen.ModalScreen`\ [\ :py:obj:`str`\ ] Modal that lets user browse and confirm a directory. .. py:attribute:: DEFAULT_CSS :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """ DirPickerScreen { align: center middle; } DirPickerScreen > Vertical { width: 80%; height: 80%; border: thick $primary; background: $surface; padding: 1; } DirPickerScreen DirectoryTree { height: 1fr; } DirPickerScreen Label { height: 1; margin-bottom: 1; } DirPickerScreen Horizontal { height: 3; align: right middle; } DirPickerScreen Button { margin-left: 1; } """ .. raw:: html
.. py:attribute:: _start :value: b'.' .. py:method:: compose() -> textual.app.ComposeResult .. py:method:: on_directory_tree_directory_selected(event: textual.widgets.DirectoryTree.DirectorySelected) -> None .. py:method:: on_button_pressed(event: textual.widgets.Button.Pressed) -> None .. py:class:: SetupPane Bases: :py:obj:`textual.widgets.Static` .. py:attribute:: DEFAULT_CSS :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """ SetupPane { padding: 1 2; } SetupPane Label { margin-top: 1; } SetupPane .path-row { height: 3; } SetupPane Input { width: 1fr; } SetupPane Button { width: 14; margin-left: 1; } SetupPane .hint { color: $text-muted; margin-bottom: 1; } """ .. raw:: html
.. py:method:: compose() -> textual.app.ComposeResult .. py:method:: on_button_pressed(event: textual.widgets.Button.Pressed) -> None .. py:method:: get_values() -> dict .. py:class:: FilesListScreen(files: list[str], pattern: str = '', mode: str = 'placeholder', fields: list[str] | None = None) Bases: :py:obj:`textual.screen.ModalScreen` Modal showing all matched files with extraction details on click. .. py:attribute:: DEFAULT_CSS :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """ FilesListScreen { align: center middle; } FilesListScreen > Vertical { width: 92%; height: 90%; border: thick $primary; background: $surface; padding: 1; } FilesListScreen DataTable { height: 1fr; } FilesListScreen #extraction-panel { height: auto; max-height: 40%; border: solid $primary; padding: 0 1; color: $success; overflow-y: auto; } FilesListScreen #extraction-panel.muted { color: $text-muted; } FilesListScreen #extraction-panel.error { color: $error; } FilesListScreen Horizontal { height: 3; align: right middle; } """ .. raw:: html
.. py:attribute:: _files .. py:attribute:: _pattern :value: '' .. py:attribute:: _mode :value: 'placeholder' .. py:attribute:: _fields :value: [] .. py:method:: compose() -> textual.app.ComposeResult .. py:method:: on_mount() -> None .. py:method:: on_data_table_row_highlighted(event: textual.widgets.DataTable.RowHighlighted) -> None .. py:method:: _show_extraction(filepath: str) -> None .. py:method:: on_button_pressed(event: textual.widgets.Button.Pressed) -> None .. py:method:: on_key(event) -> None .. py:class:: ChannelNamesScreen(filepath: str) Bases: :py:obj:`textual.screen.ModalScreen` Modal showing channel names and types from a file. .. py:attribute:: DEFAULT_CSS :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """ ChannelNamesScreen { align: center middle; } ChannelNamesScreen > Vertical { width: 70%; height: 85%; border: thick $primary; background: $surface; padding: 1; } ChannelNamesScreen DataTable { height: 1fr; } ChannelNamesScreen #ch-status { color: $text-muted; height: 1; } ChannelNamesScreen Horizontal { height: 3; align: right middle; } """ .. raw:: html
.. py:attribute:: _filepath .. py:method:: compose() -> textual.app.ComposeResult .. py:method:: on_mount() -> None .. py:method:: _load_worker() -> None .. py:method:: _populate(ch_names: list, ch_types: list) -> None .. py:method:: on_button_pressed(event: textual.widgets.Button.Pressed) -> None .. py:method:: on_key(event) -> None .. py:function:: _flatten_dict(d: dict, prefix: str = '') -> dict Flatten nested dict with dot-notation keys. .. py:class:: RulesPane Bases: :py:obj:`textual.widgets.Static` .. py:attribute:: DEFAULT_CSS :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """ RulesPane { padding: 1 2; } RulesPane Label { margin-top: 1; } RulesPane .hint { color: $text-muted; } RulesPane .pattern-examples { color: $text-muted; margin-bottom: 1; padding: 0 2; border-left: solid $primary; } RulesPane #ext-count { color: $text-muted; height: 1; margin-bottom: 1; } RulesPane #preview-row { height: auto; margin-top: 1; } RulesPane #preview-label { padding: 1; border: solid $primary; color: $success; width: 1fr; height: auto; min-height: 3; } RulesPane #preview-label.error { color: $error; } RulesPane #preview-label.muted { color: $text-muted; } RulesPane #show-files { width: 18; margin-left: 1; } RulesPane Select { margin-bottom: 1; } RulesPane Input { margin-bottom: 1; } RulesPane .section-head { margin-top: 1; } RulesPane RadioSet { margin-bottom: 1; } RulesPane #regex-fields-row { display: none; height: auto; } RulesPane #regex-fields-row.visible { display: block; } RulesPane #regex-examples { display: none; } RulesPane #regex-examples.visible { display: block; } RulesPane #io-example-row { display: none; height: auto; } RulesPane #io-examples { display: none; } RulesPane #io-src-row { height: 3; } RulesPane #io-src-row Input { width: 1fr; } RulesPane #io-src-row Button { width: 18; margin-left: 1; } RulesPane #pattern-section { height: auto; } RulesPane .inspect-row { height: 3; margin-bottom: 1; } RulesPane .inspect-row Button { margin-right: 1; } """ .. raw:: html
.. py:attribute:: _preview_lock :type: ClassVar .. py:attribute:: _preview_timer :value: None .. py:attribute:: _matched_files :type: list[str] :value: [] .. py:method:: compose() -> textual.app.ComposeResult .. py:method:: on_input_changed(event: textual.widgets.Input.Changed) -> None .. py:method:: on_select_changed(event: textual.widgets.Select.Changed) -> None .. py:method:: on_radio_set_changed(event: textual.widgets.RadioSet.Changed) -> None .. py:method:: on_button_pressed(event: textual.widgets.Button.Pressed) -> None .. py:method:: _get_mode_and_fields() -> tuple[str, list[str]] .. py:method:: _get_io_example() -> tuple[str, str] .. py:method:: _schedule_ext_count() -> None .. py:method:: _run_ext_count() -> None .. py:method:: _ext_count_worker(source: str, ext: str) -> None .. py:method:: _psd_worker(filepath: str) -> None .. py:method:: _schedule_preview() -> None .. py:method:: _run_preview() -> None .. py:method:: _preview_worker(source: str, pattern: str, ext: str, mode: str, fields: list[str], io_src: str = '', io_tgt: str = '') -> None .. py:method:: _update_show_files_btn(files: list[str]) -> None .. py:method:: _set_preview(text: str, css_class: str) -> None .. py:method:: _get_source() -> str .. py:method:: get_rules() -> dict .. py:class:: MappingsPane Bases: :py:obj:`textual.widgets.Static` .. py:attribute:: DEFAULT_CSS :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """ MappingsPane { padding: 1 2; } MappingsPane #mappings-status { margin-bottom: 1; color: $text-muted; } MappingsPane DataTable { height: 1fr; } MappingsPane Horizontal { height: 3; margin-bottom: 1; } MappingsPane Button { margin-right: 1; } """ .. raw:: html
.. py:attribute:: _mappings :type: textual.reactive.reactive[list] .. py:method:: compose() -> textual.app.ComposeResult .. py:method:: on_mount() -> None .. py:method:: on_button_pressed(event: textual.widgets.Button.Pressed) -> None .. py:method:: _generate() -> None .. py:method:: _gen_worker(source: str, bids: str, rules: dict) -> None .. py:method:: _populate_table(individuals: list) -> None .. py:method:: _save_mappings_yaml() -> None .. py:method:: _set_status(msg: str, error: bool = False) -> None .. py:class:: ConvertPane Bases: :py:obj:`textual.widgets.Static` .. py:attribute:: DEFAULT_CSS :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """ ConvertPane { padding: 1 2; } ConvertPane Horizontal { height: 3; margin-bottom: 1; } ConvertPane Button { margin-right: 1; } ConvertPane RichLog { height: 1fr; border: solid $primary; } """ .. raw:: html
.. py:method:: compose() -> textual.app.ComposeResult .. py:method:: on_button_pressed(event: textual.widgets.Button.Pressed) -> None .. py:method:: _start_convert() -> None .. py:method:: _convert_worker(mapping_data: dict) -> None .. py:method:: _log(msg: str) -> None .. py:class:: SovabidsApp Bases: :py:obj:`textual.app.App` sovabids TUI — EEG to BIDS conversion wizard. .. py:attribute:: TITLE :value: 'sovabids' .. py:attribute:: SUB_TITLE :value: 'EEG → BIDS conversion' .. py:attribute:: CSS :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """ TabbedContent { height: 1fr; } TabPane { height: 1fr; } """ .. raw:: html
.. py:attribute:: BINDINGS :value: [('q', 'quit', 'Quit'), ('ctrl+s', 'save_rules', 'Save rules')] .. py:attribute:: _mapping_data :type: dict | None :value: None .. py:attribute:: _pending_input_id :type: str :value: '' .. py:method:: compose() -> textual.app.ComposeResult .. py:method:: _on_dir_picked(path: str) -> None .. py:method:: action_save_rules() -> None .. py:function:: main() -> None