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