xref: /aosp_15_r20/external/pigweed/pw_console/plugins.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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