1.. _module-pw_console-plugins: 2 3============ 4Plugin Guide 5============ 6.. pigweed-module-subpage:: 7 :name: pw_console 8 9Pigweed Console supports extending the user interface with custom widgets. For 10example: Toolbars that display device information and provide buttons for 11interacting with the device. 12 13--------------- 14Writing Plugins 15--------------- 16Creating new plugins has a few high level steps: 17 181. Create a new Python class inheriting from either `WindowPane`_ or 19 `WindowPaneToolbar`_. 20 21 - Optionally inherit from The ``PluginMixin`` class as well for running 22 background tasks. 23 242. Enable the plugin before pw_console startup by calling ``add_window_plugin``, 25 ``add_floating_window_plugin``, ``add_top_toolbar`` or 26 ``add_bottom_toolbar``. See the 27 :ref:`module-pw_console-embedding-plugins` section of the 28 :ref:`module-pw_console-embedding` for an example. 29 303. Run the console and enjoy! 31 32 - Debugging Plugin behavior can be done by logging to a dedicated Python 33 logger and viewing in-app. See `Debugging Plugin Behavior`_ below. 34 35Background Tasks 36================ 37Plugins may need to have long running background tasks which could block or slow 38down the Pigweed Console user interface. For those situations use the 39``PluginMixin`` class. Plugins can inherit from this and setup the callback that 40should be executed in the background. 41 42.. autoclass:: pw_console.plugin_mixin.PluginMixin 43 :members: 44 :show-inheritance: 45 46Debugging Plugin Behavior 47========================= 48If your plugin uses background threads for updating it can be difficult to see 49errors. Often, nothing will appear to be happening and exceptions may not be 50visible. When using ``PluginMixin`` you can specify a name for a Python logger 51to use with the ``plugin_logger_name`` keyword argument. 52 53.. code-block:: python 54 55 class AwesomeToolbar(WindowPaneToolbar, PluginMixin): 56 57 def __init__(self, *args, **kwargs): 58 super().__init__(*args, **kwargs) 59 self.update_count = 0 60 61 self.plugin_init( 62 plugin_callback=self._background_task, 63 plugin_callback_frequency=1.0, 64 plugin_logger_name='my_awesome_plugin', 65 ) 66 67 def _background_task(self) -> bool: 68 self.update_count += 1 69 self.plugin_logger.debug('background_task_update_count: %s', 70 self.update_count) 71 return True 72 73This will let you open up a new log window while the console is running to see 74what the plugin is doing. Open up the logger name provided above by clicking in 75the main menu: :guilabel:`File > Open Logger > my_awesome_plugin`. 76 77-------------- 78Sample Plugins 79-------------- 80Pigweed Console will provide a few sample plugins to serve as templates for 81creating your own plugins. These are a work in progress at the moment and not 82available at this time. 83 84Bandwidth Toolbar 85================= 86Tracks and logs the data sent and received over a serial transport like a socket 87or PySerial device. To use in a custom transport interface instantiate the 88``SerialBandwidthTracker`` and call ``track_read_data`` on incoming data bytes 89and ``track_write_data`` on outoing data bytes. 90 91Calculator 92========== 93This plugin is similar to the full-screen `calculator.py example`_ provided in 94prompt_toolkit. It's a full window that can be moved around the user interface 95like other Pigweed Console window panes. An input prompt is displayed on the 96bottom of the window where the user can type in some math equation. When the 97enter key is pressed the input is processed and the result shown in the top half 98of the window. 99 100Both input and output fields are prompt_toolkit `TextArea`_ objects which can 101have their own options like syntax highlighting. 102 103.. figure:: images/calculator_plugin.svg 104 :alt: Screenshot of the CalcPane plugin showing some math calculations. 105 106 Screenshot of the ``CalcPane`` plugin showing some math calculations. 107 108The code is heavily commented and describes what each line is doing. See 109the :ref:`calc_pane_code` for the full source. 110 111Clock 112===== 113The ClockPane is another WindowPane based plugin that displays a clock and some 114formatted text examples. It inherits from both WindowPane and PluginMixin. 115 116.. figure:: images/clock_plugin1.svg 117 :alt: ClockPane plugin screenshot showing the clock text. 118 119 ``ClockPane`` plugin screenshot showing the clock text. 120 121This plugin makes use of PluginMixin to run a task a background thread that 122triggers UI re-draws. There are also two toolbar buttons to toggle view mode 123(between the clock and some sample text) and line wrapping. pressing the 124:kbd:`v` key or mouse clicking on the :guilabel:`View Mode` button will toggle 125the view to show some formatted text samples: 126 127.. figure:: images/clock_plugin2.svg 128 :alt: ClockPane plugin screenshot showing formatted text examples. 129 130 ``ClockPane`` plugin screenshot showing formatted text examples. 131 132Like the CalcPane example the code is heavily commented to guide plugin authors 133through developmenp. See the :ref:`clock_pane_code` below for the full source. 134 1352048 Game 136========= 137This is a plugin that demonstrates more complex user interaction by playing a 138game of 2048. 139 140Similar to the ``ClockPane`` the ``Twenty48Pane`` class inherits from 141``PluginMixin`` to manage background tasks. With a few differences: 142 143- Uses ``FloatingWindowPane`` to create a floating window instead of a 144 standard tiled window. 145- Implements the ``get_top_level_menus`` function to create a new ``[2048]`` 146 menu in Pigweed Console's own main menu bar. 147- Adds custom game keybindings which are set within the ``Twenty48Control`` 148 class. That is the prompt_toolkit ``FormattedTextControl`` widget which 149 receives keyboard input when the game is in focus. 150 151The ``Twenty48Game`` class is separate from the user interface and handles 152managing the game state as well as printing the game board. The 153``Twenty48Game.__pt_formatted_text__()`` function is responsible for drawing the 154game board using prompt_toolkit style and text tuples. 155 156.. figure:: images/2048_plugin1.svg 157 :alt: Twenty48Pane plugin screenshot showing the game board. 158 159 ``Twenty48Pane`` plugin screenshot showing the game board. 160 161-------- 162Appendix 163-------- 164.. _calc_pane_code: 165 166Code Listing: ``calc_pane.py`` 167============================== 168.. literalinclude:: ./py/pw_console/plugins/calc_pane.py 169 :language: python 170 :linenos: 171 172.. _clock_pane_code: 173 174Code Listing: ``clock_pane.py`` 175=============================== 176.. literalinclude:: ./py/pw_console/plugins/clock_pane.py 177 :language: python 178 :linenos: 179 180.. _twenty48_pane_code: 181 182Code Listing: ``twenty48_pane.py`` 183================================== 184.. literalinclude:: ./py/pw_console/plugins/twenty48_pane.py 185 :language: python 186 :linenos: 187 188 189.. _WindowPane: https://cs.pigweed.dev/pigweed/+/main:pw_console/py/pw_console/widgets/window_pane.py 190.. _WindowPaneToolbar: https://cs.pigweed.dev/pigweed/+/main:pw_console/py/pw_console/widgets/window_pane_toolbar.py 191.. _calculator.py example: https://github.com/prompt-toolkit/python-prompt-toolkit/blob/3.0.23/examples/full-screen/calculator.py 192.. _TextArea: https://python-prompt-toolkit.readthedocs.io/en/latest/pages/reference.html#prompt_toolkit.widgets.TextArea 193