Source code for main_ui

# Copyright (C) 2020  Alex Sonea

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

from typing import Dict
from snack import SnackScreen, Widget


[docs]class MainUI(): """Main UI class that handles the views and switches between them. The MainUI setups a SnackScreen, determines the size of the available screen and handles the main display loop that processes the hotkeys. An additional hot-key 'q' is provided to quit the loop and close the display. """ screen: SnackScreen """The main screen of the UI. It is a SnackScreen.""" w: int """The width of the screen.""" h: int """The height of the screen.""" views: Dict[str, Widget] """The views in the UI. You can use :meth:`add_view()` to add them to this dictionary.""" current_view: Widget """The current view being shown.""" done: bool """Controls the display loop. Will be initialized to `False` and will only be set to `True` by pressing the ``q`` hot-key."""
[docs] def __init__(self) -> None: """Initializes the UI. Allocates the SnackScreen, determines the width and height of the screen and initializes the views. """ # setup the graphics self.screen = SnackScreen() # for convenience self.w = self.screen.width self.h = self.screen.height # main window self.views = {} self.current_view = None self.done = False
[docs] def add_view(self, view: Widget, hot_key: str, default_view: bool = False) -> None: """Adds a view (page) to the dictionay of views. Views are held by their hotkey. Parameters ---------- view : Widget or subclass The view (page) to be added. The view must be fully constructed and :meth:`view_ui.View.run()` must be possible to be executed on that object. hot_key : str The key associated with the view. The main loop will process keys and if they match one of these it will handle the switch to that particular view. default_view : bool, optional Marks this view as the default view which means the MainUI will use this to start displaying the interface when executing :meth:`run()` for the first time. When you add views to the MainUI the last one that uses the ``default_view`` will overwrite the other ones and that will be the one to be used. If no view is defined as ``default_view`` the MainUI will use the first item in the list of hot-keys. Because of the way the dictionaries work in Python this might not be the first view added. By default `False` """ self.views[hot_key] = view if default_view: self.default_view = hot_key
[docs] def change_view(self, hotkey: str) -> None: """Changes a view to the one specified by the hot-key provided. The method will ask the present view to :meth:`view_ui.View.finish()` then will `popWindow()` from the screen. It will assign the view represented in the dictionary by the ``hotkey`` to the ``current_view``, it will ask to :meth:`view_ui.View.setup()`, and will setup the hot-keys from that view. Parameters ---------- hotkey : str The hot-key identifying that view. """ if self.current_view: self.current_view.finish() self.screen.popWindow() self.current_view = self.views[hotkey] self.current_view.setup() for key in self.views.keys(): self.current_view.grid.addHotKey(key) self.current_view.grid.addHotKey('q')
[docs] def run(self) -> None: """Runs the main loop of the UI. It will activate the ``default_view`` and then will execute a :meth:`view_ui.View.run()` for that view (which for shack means to wait for a key press) then handle the hotkeys by switching the views if they match the ones associated with the views or finish the loop if 'q' was pressed. .. Note: The actual refresh of values inside the views is done by the timer that is created by the view itself. See the class View for details. """ if not self.default_view: self.default_view = list(self.views.keys())[0] self.change_view(self.default_view) while not self.done: key = self.current_view.run() if key == 'q': self.done = True if key in self.views: self.change_view(key) # finish the loop self.screen.popWindow() self.screen.finish()