.. _uiscreen_label: UIScreen ======== .. automodule:: simpleline.render.screen The base class for creating a new screen. :class:`UIScreen` is used for any user interaction. :class:`UIScreen` uses :ref:`containers ` and :ref:`widgets ` to present information to a user, and the :meth:`UIScreen.input` method to get input from a user to an application. Screens are pushed to the screen stack, which are then used to communicate with a user. See the :ref:`screen handling ` section to find out more. The methods :meth:`UIScreen.redraw`, :meth:`UIScreen.close`, :meth:`UIScreen.emit` and :meth:`UIScreen.create_and_emit` are asynchronous. These methods will create a signal which is passed to the event loop for later processing. **Beware**, methods :meth:`UIScreen.redraw` and :meth:`UIScreen.close` can lead to unexpected behavior when multiple instances of these signals are emitted (methods are called multiple times). This can even crash your application. Lifecycle --------- Every :class:`UIScreen` has a distinct lifecycle: *uninitialized*, *initialized*, *draw*, *process input* and *closed*. If the screen has already been initialized (it was *drawn* to a monitor) and will be shown again, then the screen skips the *uninitialized* stage. The screen can cycle between *draw* and *process input* stages by calling the :meth:`UIScreen.redraw` method after processing user input. In case :meth:`UIScreen.redraw` won't be called and no new screen is pushed, or this screen wasn't closed, then an application will stay in an infinite loop waiting for something to happen. This is correct behavior because there could be something in an event loop which will call :meth:`UIScreen.redraw` later. Rendering widgets ----------------- The :meth:`UIScreen.refresh` method is the most important part of the :class:`UIScreen`. It contains preparations for rendering (creating widgets and adding them to containers). The :meth:`UIScreen.refresh` method will be called before anything is drawn on a monitor. The :attr:`UIScreen.window` attribute, which is the :class:`WindowContainer ` instance, contains all items (widgets, containers) which are to be rendered by the screen. A new :class:`WindowContainer ` is created in the :meth:`UIScreen.refresh` method for every screen redraw. The :attr:`UIScreen.title` attribute is passed to the :attr:`WindowContainer.title ` property, and a developer can add :ref:`widgets ` and other :ref:`containers ` to present items to a user by calling :meth:`WindowContainer.add() ` or :meth:`WindowContainer.add_with_separator() `. Multiple items can be added by calling these methods repeatedly. When everything is prepared properly in the :meth:`UIScreen.refresh` method, it needs to be drawn on the monitor for a user. This is handled by the :meth:`UIScreen.show_all` method. This method works automatically, but it could also be useful for a developer, especially when the screen will not process input. In this case, the :meth:`UIScreen.input` method is not called at all. Developers can override this method and call the parent class's :meth:`UIScreen.show_all`, which will handle drawing the screen and any additional processing. Redrawing the screen can be invoked by the :meth:`UIScreen.redraw` method. However, this is not processed immediately. Instead it will be added to the event loop and processed later, when the loop is idle. Beware, after every :meth:`redraw ` call the input is processed if not disabled, so if multiple redraw signals are emitted, than the application will crash. The :meth:`UIScreen.redraw` method is also invoked when a screen is :ref:`pushed ` to the stack. User input processing --------------------- If the screen shouldn't process user input, the :attr:`UIScreen.input_required` property needs to be set to `False`. `True` is the default value for this property. After everything is printed to a monitor, the :class:`UIScreen` will wait for user input. For this purpose there is :meth:`UIScreen.input`, which is called when a user passes string input to a screen. The screen needs to react upon user input and return one of the options from the :class:`InputState` enum or the user input string. To accept the user input, :attr:`InputState.PROCESSED`, :attr:`InputState.PROCESSED_AND_REDRAW` or :attr:`InputState.PROCESSED_AND_CLOSE` should be returned. Addition to accepting user input the :attr:`InputState.PROCESSED_AND_REDRAW` value will also redraw active screen and :attr:`InputState.PROCESSED_AND_CLOSE` will close active screen. However, if :attr:`InputState.PROCESSED` is used then the developer is responsible for not ending in frozen application. The :meth:`UIScreen.refresh` or the :meth:`UIScreen.close` methods must be called manually. In case the user input is invalid, the :attr:`InputState.DISCARDED` value should be returned. This will reject the user input and wait for another attempt. The :class:`UIScreen.refresh` method will be called after 5 rejections and show the screen output again. If the user input string is returned it will be checked for options of the :class:`Prompt ` instance which can either close the screen, refresh the screen (this will call :meth:`UIScreen.refresh`) or quit the application. Closing screens --------------- There are several ways to close a screen. One is by calling :meth:`UIScreen.close` or by pressing *c* to continue (with the default :class:`Prompt ` class). When the screen is closed the next screen on the stack will be shown. A screen can also be :ref:`replaced `. Then the original screen is removed from the stack without closing a screen. If a reaction on closing a screen is required then the :meth:`UIScreen.closed` callback should be overridden. **Beware**, when calling :meth:`UIScreen.close` multiple times it will close multiple screens. This is because the close signal will always close the top screen on the screen stack. UIScreen class -------------- .. autoclass:: UIScreen :members: :inherited-members: InputState enum --------------- .. autoclass:: InputState :members: :undoc-members: