spacr.gui_utils
===============

.. py:module:: spacr.gui_utils








Module Contents
---------------

.. py:function:: attach_dependency_listeners(vars_dict, categories, category_dependencies, category_group_dependencies)

   Wire up show/hide dependencies between boolean settings and categories.

   Registers trace callbacks so toggling a boolean widget hides or shows every
   dependent category, supporting both 1:1 dependencies and any-of group
   dependencies. Initial visibility is applied immediately.

   :param vars_dict: mapping ``key -> (label, widget, var, frame)``.
   :param categories: mapping of category name to the list of settings it owns.
   :param category_dependencies: mapping ``bool_key -> [categories to toggle]``.
   :param category_group_dependencies: mapping ``category -> [bool_keys that any-enable it]``.
   :returns: None.


.. py:function:: initialize_cuda()

   Initialize CUDA in the main process by performing a trivial GPU op.

   :returns: None.


.. py:function:: set_high_priority(process)

   Raise the OS scheduling priority of a subprocess.

   Uses ``HIGH_PRIORITY_CLASS`` on Windows and ``nice(-10)`` on Unix-like systems.
   Failures are logged but never raised.

   :param process: a ``multiprocessing.Process`` (or object exposing ``.pid``).
   :returns: None.


.. py:function:: set_cpu_affinity(process)

   Pin a subprocess to all available CPU cores on Linux.

   No-op on non-Linux platforms.

   :param process: a ``multiprocessing.Process`` (or object exposing ``.pid``).
   :returns: None.


.. py:function:: proceed_with_app(root, app_name, app_func)

   Replace ``root.content_frame`` contents with a new app.

   :param root: the Tk root that owns ``content_frame``.
   :param app_name: display name of the app (currently unused, kept for logging/hooks).
   :param app_func: callable invoked with ``root.content_frame`` to build the new app.
   :returns: None.


.. py:function:: load_app(root, app_name, app_func)

   Tear down the current spacr app and load another in its place.

   Cancels pending ``after`` tasks and defers the swap to the current app's
   exit hook when one is registered (annotation/make_masks apps swap
   immediately since they own the root themselves).

   :param root: the Tk root.
   :param app_name: name of the app to load.
   :param app_func: callable invoked with ``root.content_frame`` to build it.
   :returns: None.


.. py:function:: parse_list(value)

   Parse a string literal into a homogeneous list of scalars.

   Accepts Python-list or tuple literals and rejects mixed-type contents.
   Single-element tuples are returned as one-element lists.

   :param value: string representation of a list or tuple.
   :returns: parsed list containing only ints, floats, or strings.
   :raises ValueError: if the string is not a valid literal or contains
       mixed / unsupported types.


.. py:function:: create_input_field(frame, label_text, row, var_type='entry', options=None, default_value=None)

   Create a labeled settings input widget on ``frame`` at ``row``.

   Supports entry, checkbox and combo variants and coerces ``default_value``
   to the widget's expected type; unrecognised ``var_type`` returns a bare
   label with no widget.

   :param frame: parent frame that hosts the row.
   :param label_text: raw settings key; underscores are replaced with spaces
       and the first letter capitalised for display.
   :param row: grid row inside ``frame`` to occupy.
   :param var_type: one of ``'entry'``, ``'check'``, ``'combo'``.
   :param options: list of choices used when ``var_type='combo'``.
   :param default_value: initial value; falls back to a type-appropriate default.
   :returns: tuple ``(label, widget, tk_var, container_frame)``.


.. py:function:: process_stdout_stderr(q)

   Redirect ``sys.stdout`` and ``sys.stderr`` writes into a queue.

   :param q: queue receiving each written message.
   :returns: None.


.. py:class:: WriteToQueue(q)

   Bases: :py:obj:`io.TextIOBase`


   File-like sink that forwards writes into a queue.

   Used to reroute ``stdout``/``stderr`` into the GUI console.

   :param q: queue receiving each non-empty write.


   .. py:attribute:: q


   .. py:method:: write(msg)

      Forward a non-empty message to the queue.



   .. py:method:: flush()

      No-op required by the file-like interface.



.. py:function:: cancel_after_tasks(frame)

   Cancel every scheduled Tk ``after`` task tracked on ``frame``.

   :param frame: Tk widget with an ``after_tasks`` attribute.
   :returns: None.


.. py:function:: annotate(settings)

   Launch the standalone annotation UI on a measurements database.

   Ensures the requested annotation column exists in the ``png_list`` table,
   then opens ``AnnotateApp`` in its own Tk root and blocks on the mainloop.

   :param settings: annotation settings dict (see ``set_annotate_default_settings``).
   :returns: None.


.. py:function:: generate_annotate_fields(frame)

   Build labelled entry widgets for the annotation-settings defaults.

   :param frame: parent Tk frame that hosts the field grid.
   :returns: mapping ``key -> {'entry': ttk.Entry, 'value': default}``.


.. py:function:: run_annotate_app(vars_dict, parent_frame)

   Collect the annotation-fields values, coerce types, and start the annotator.

   Clears ``parent_frame`` of existing widgets before launching the app.

   :param vars_dict: widget map produced by :func:`generate_annotate_fields`.
   :param parent_frame: Tk frame that hosts the annotation UI.
   :returns: None.


.. py:data:: global_image_refs
   :value: []


.. py:function:: annotate_app(parent_frame, settings)

   Start the annotation app inside an existing GUI frame.

   :param parent_frame: Tk frame whose toplevel hosts the annotator.
   :param settings: annotation settings dict.
   :returns: None.


.. py:function:: load_next_app(root)

   Invoke the queued next-app callback, reinitialising root if it was destroyed.

   :param root: current Tk root; expected to hold ``next_app_func`` and ``next_app_args``.
   :returns: None.


.. py:function:: annotate_with_image_refs(settings, root, shutdown_callback)

   Start ``AnnotateApp`` inside an existing root with a shutdown chain.

   Ensures the annotation column exists in the ``png_list`` table, sizes the
   root to the full screen, and registers an exit hook that runs
   ``shutdown_callback`` after the app closes.

   :param settings: annotation settings dict.
   :param root: existing Tk root to reuse.
   :param shutdown_callback: callable invoked after the annotator shuts down.
   :returns: None.


.. py:function:: convert_settings_dict_for_gui(settings)

   Convert a plain settings dict into the GUI variable spec.

   Maps each key to a ``(widget_type, options, default_value)`` triple, using
   combo boxes for keys with known enumerated options and inferring
   check/entry widgets otherwise.

   :param settings: mapping of setting names to default values.
   :returns: mapping ``key -> (var_type, options, default_value)`` ready for
       :func:`create_input_field`.


.. py:function:: spacrFigShow(fig_queue=None)

   Route matplotlib figures into a queue instead of displaying them.

   Drop-in replacement for ``plt.show()`` used while spacr runs inside the GUI
   process; falls back to ``fig.show()`` when no queue is provided.

   :param fig_queue: queue that receives the current figure, or None.
   :returns: None.


.. py:function:: function_gui_wrapper(function=None, settings=None, q=None, fig_queue=None, imports=1)

   Run a spacr worker function with GUI-safe stdout, error and figure routing.

   Temporarily replaces ``plt.show`` with :func:`spacrFigShow` so any figures
   are shipped to ``fig_queue`` instead of blocking, and forwards exception
   text to ``q``.

   :param function: worker callable to invoke.
   :param settings: settings dict passed to ``function``.
   :param q: queue for log/error messages sent to the GUI.
   :param fig_queue: queue for matplotlib figures produced during the run.
   :param imports: 1 to call ``function(settings=...)``; 2 to call
       ``function(src=settings['src'], settings=...)``.
   :returns: None.


.. py:function:: run_function_gui(settings_type, settings, q, fig_queue, stop_requested)

   Dispatch a spacr module by ``settings_type`` and run it in the worker.

   Redirects stdout/stderr into ``q``, invokes the mapped module via
   :func:`function_gui_wrapper`, and sets ``stop_requested`` on completion so
   the GUI can reap the process.

   :param settings_type: identifier that selects the target spacr function.
   :param settings: settings dict passed through to the worker.
   :param q: queue for log/error messages.
   :param fig_queue: queue for matplotlib figures.
   :param stop_requested: shared ``multiprocessing.Value('i')`` flipped to 1 on exit.
   :returns: None.
   :raises ValueError: if ``settings_type`` is not a recognised module.


.. py:function:: hide_all_settings(vars_dict, categories=None)

   Hide every widget that belongs to any known category.

   Used to collapse all optional-category settings until their triggering
   boolean is toggled on.

   :param vars_dict: mapping ``key -> (label, widget, var, frame)``.
   :param categories: category-to-settings map; if None, ``vars_dict`` is returned unchanged.
   :returns: the (mutated) ``vars_dict``.


.. py:function:: setup_frame(parent_frame)

   Build the settings/plot/console panel layout inside ``parent_frame``.

   Creates the horizontal-split PanedWindow, a vertical container for figures
   and a horizontal container for buttons, and applies the dark theme.

   :param parent_frame: Tk frame that will host the layout.
   :returns: tuple ``(parent_frame, vertical_container, horizontal_container, settings_container)``.


.. py:function:: download_hug_dataset(q, vars_dict)

   Download the demo dataset and settings pack from Hugging Face.

   Also updates ``vars_dict['src']`` with the downloaded dataset path so the
   settings panel points at it. Progress and errors are reported through ``q``.

   :param q: queue used for status/error messages.
   :param vars_dict: settings widget map; the ``'src'`` entry is updated if present.
   :returns: None.


.. py:function:: download_dataset(q, repo_id, subfolder, local_dir=None, retries=5, delay=5)

   Download a Hugging Face dataset subfolder (or CSVs) to a local directory.

   Skips the download if the target directory already contains files, and
   retries transient HTTP errors per-file and per-listing.

   :param q: queue used for progress/error messages.
   :param repo_id: HF dataset repo id (e.g. ``'einarolafsson/toxo_mito'``).
   :param subfolder: subfolder within the repo; empty string downloads top-level CSVs.
   :param local_dir: destination directory; defaults to ``~/datasets``.
   :param retries: number of retry attempts for both listing and each file.
   :param delay: delay in seconds between retries.
   :returns: path to the local directory containing the downloaded files.
   :raises Exception: if downloads fail after all retry attempts.


.. py:function:: ensure_after_tasks(frame)

   Ensure ``frame.after_tasks`` exists so scheduled callbacks can be tracked.

   :param frame: Tk widget to annotate.
   :returns: None.


.. py:function:: display_gif_in_plot_frame(gif_path, parent_frame)

   Loop a GIF in ``parent_frame``, cover-cropped and cached per frame size.

   :param gif_path: filesystem path to the GIF.
   :param parent_frame: Tk frame that hosts the animation.
   :returns: None.


.. py:function:: display_media_in_plot_frame(media_path, parent_frame)

   Loop an MP4/AVI/GIF in ``parent_frame``, cover-cropped to fill it.

   :param media_path: path to the media file; extension picks the decoder.
   :param parent_frame: Tk frame that hosts the playback.
   :returns: None.
   :raises ValueError: for unsupported file extensions.


.. py:function:: print_widget_structure(widget, indent=0)

   Print the Tk widget tree rooted at ``widget`` for debugging.

   :param widget: root widget to descend from.
   :param indent: current indent depth (spaces) used by recursive calls.
   :returns: None.


.. py:function:: get_screen_dimensions()

   Return the pixel dimensions of the primary monitor.

   :returns: tuple ``(screen_width, screen_height)`` in pixels.


.. py:function:: convert_to_number(value)

   Convert a string to ``int`` when possible, otherwise to ``float``.

   :param value: string representation of a number.
   :returns: parsed number as ``int`` (preferred) or ``float``.
   :raises ValueError: if the string is neither.


